C ++ Type Casting: is it useful to use explicit casts?

What are the benefits of using these operators instead of implicit casting in C ++?

dynamic_cast <new_type> (expression) reinterpret_cast <new_type> (expression) static_cast <new_type> (expression) 

Why, where, in what situation should we use them? And is it true that they are rarely used in OOP?

+4
source share
6 answers

From the list of casts you provided, the only thing that makes sense to use to support an implicit cast is static_cast.

dynamic_cast is used to downgrade a superclass to its subclass. This cannot happen implicitly and in fact is something that is not so rare in OOP. static_cast can also be used in such castings, however it is more dangerous, since it does not check during runtime that downcast is valid.

The last cast, reinterpret_cast, should be used very carefully, as it is the most dangerous of all. You can essentially do something about it - but you, as a programmer, will have to make sure that such an actor makes sense semantically, since you essentially disable type checking by doing this selection.

+7
source

Like any other implicit thing, it can hide logic that the developer / reviewer did not have in mind, masking errors.

+3
source

As a rule, I saw how these types of casts appear in the code when something is no longer being created, perhaps because we started using a new compiler, which is more strict with respect to implicit conversions, so that the key β€œbenefits” from implicit conversions , Obviously, the right thing in this situation is to change the code in some other way!

Dynamic_cast can be used for upstream casting with polymorphism. So, if you have such a structure,

Base β†’ Derivative A

Base β†’ Derivative B

you can do dynamic_cast (b); (b is a pointer to Base, but is actually Derived_B);

If it were not for the Derived_B class, you would get 0 instead of 0 of the converted pointer.

This is much slower than static_cast, since the check is performed at runtime, not compile time, but the intended use is different.

reinterpret_cast simply changes the type label, allowing a funky C-style FX (or "type-punning" is usually called), useful for protocol / low level operation, but should be used sparingly.

Typically, a lot of codes in a code is a sign that something is wrong with your code design.

+2
source

For a very short answer, the advantages of these drives are that they perform certain functions, making the code descriptive. The C-style summary is omnipotent and avoids trouble with all possible errors. Those accustomed to C may complain that throws are a pain to write out. This was actually considered a good friend: it does not encourage programmers to sprinkle all the code, which is a very obvious sign of problematic code. Finally, they are easy to find using text search.

+2
source

One of the advantages of using C ++ translations instead of C-style is that they are easily searchable. They also separate the various applications from the C-style, making smells easily identifiable.

For example, grep for reinterpret_cast can easily find many potential problems and bad designs, while a regular expression that correctly identifies C-style dropbacks needs additional testing to identify bad roles.

If you need cast, I will always use C ++, not C-style.

See C ++ Coding Standards, Sutter and Alexandrescu, paragraph 95.

+1
source

I just want to add an example of a situation where reinterpret_cast is used. Imagine a library giving you a pointer to a raw network packet. To understand the data structure, you can use structures and then overlay pointers to these structures. Note that the compiler cannot verify that you are doing something sensible here or just reading in memory where you shouldn't. In a real situation, you should first check the package size to claim that it is large enough for your structures to fit.

In the code below, the IPfragment constructor receives the packet and then passes that pointer to something sensible. I have added definitions below.

If someone still thinks that using reinterpret_cast is unreasonable, I am glad that there is a better way to do this.

 IPfragment::IPfragment( const byte* const pkt_data ) : ethernetHeader( reinterpret_cast< const EthernetHeader* >( pkt_data ) ) , ipHeader ( reinterpret_cast< const IPheader* >( pkt_data + ETHER_HEADER_LEN ) ) , payload ( reinterpret_cast< const byte* >( ipHeader ) + ( ipHeader->ver_hl & 0x0f ) *4 ) { } 

These are the definitions:

 typedef uint8_t byte ; typedef uint16_t word ; typedef uint32_t dword ; #define ETHER_ADDR_LEN 6 // Ethernet addresses are 6 bytes #define ETHER_HEADER_LEN 14 // Ethernet headers are 14 bytes #define ETHER_TYPE_IP4 8 struct EthernetHeader { byte etherDestHost[ETHER_ADDR_LEN]; // Destination host address byte etherSrcHost [ETHER_ADDR_LEN]; // Source host address word etherType; // IP? ARP? RARP? etc }; /* 4 bytes IP address */ struct IPaddress { byte byte1, byte2, byte3, byte4; }; /* IPv4 header */ struct IPheader { byte ver_hl ; // Version (4 bits) + Internet header length (4 bits) byte tos ; // Type of service word tlen ; // Total length word identification ; // Identification word flags_fo ; // Flags (3 bits) + Fragment offset (13 bits) byte ttl ; // Time to live byte proto ; // Protocol word crc ; // Header checksum IPaddress saddr ; // Source address IPaddress daddr ; // Destination address dword op_pad ; // Option + Padding }; class IPfragment { public: const IPheader* const ipHeader; const EthernetHeader* const ethernetHeader; const byte* const payload; IPfragment( const byte* const pkt_data ); // rest of code omitted for brevity } 
0
source

Source: https://habr.com/ru/post/1313735/


All Articles