Regular cast vs. static_cast vs. dynamic_cast [duplicate]

Question!

I've been writing C and C++ code for almost twenty years, but there's one aspect of these languages that I've never really understood. I've obviously used regular casts i.e.

MyClass *m = (MyClass *)ptr;

all over the place, but there seem to be two other types of casts, and I don't know the difference. What's the difference between the following lines of code?

MyClass *m = (MyClass *)ptr;
MyClass *m = static_cast<MyClass *>(ptr);
MyClass *m = dynamic_cast<MyClass *>(ptr);


Answers

static_cast

static_cast does compile-time, not run-time checking of the types involved. In many situations, this can make it the safest type of cast, as it provides the least room for accidental/unsafe conversions between various types.

However, a very important caveat to this is that, due to its lack of runtime checking, static_cast will - and indeed, must - allow a base class to be downcast to a pointer-to-derived. This can then be used to invoke undefined behaviour unless used very carefully. See, for example: Should static_cast<Derived *>(Base pointer) give compile time error?

Unless you have provided overloaded conversion operators, static_cast only allows casting between related types, such as pointers or references between Base and Derived, or between fundamental types, such as long to int or int to float.

If you have provided an implicit conversion operator T(), static_cast<T>(otherType) can then be used. If you have provided an explicit conversion operator, static_cast is required to signal deliberate intent to cast.

dynamic_cast

dynamic_cast exists to facilitate run-time checking/conversion from a base class to one of its derived classes, via references or pointers to both.

If the instance cannot be cast to a derived type, dynamic_cast will raise a runtime exception std::bad_cast when attempted on references, or return a nullptr when applied to pointers.

Due to its purpose being casting down an inheritance hierarchy, dynamic_cast works only when the source type is polymorphic. Otherwise, the compiler will give an error, e.g. error: cannot dynamic_cast 'b' (of type 'class base*') to type 'class inh1*' (source type is not polymorphic)

Examples of static_cast and/vs dynamic_cast

If we have the following classes

class B {};

class D : B {};

then you can do the following

B* b = new D();
D* d1 = static_cast<D*>b; // Valid! d1 is a valid and correct pointer to a D
D* d2 = dynamic_cast<D*>b; // Valid! d2 is a valid and correct pointer to a D

In this example, both pointers d1 and d2 will point to a correctly typed version of b as requested.

A potential for mishap where static_cast can be more unsafe than dynamic_cast is illustrated by the following example:

B* b = new B();
D* d1 = static_cast<D*>b; // works, but D component is invalid!
D* d2 = dynamic_cast<D*>b; // cast fails => d2 is now a nullptr

Now d1 will point to a data segment of type D*, but the actual data is B*, so attempting to access D-specific member is undefined behaviour. d2, on the other hand, will be a nullptr and can be checked and handled correctly (i.e. do not try to use it as a D if it failed to convert).

Because dynamic_cast performs runtime type checking, it is slower, but whether this matters to your application should be checked by benchmarking.

Since dynamic_cast can incur extra runtime cost, it can be turned off by instructing the compiler not to include Run-Time Type Information (RTTI), but this ability is compiler-specific and not a feature of the C++ standard.

There are also other cast operators:

reinterpret_cast

reinterpret_cast disregards all kind of type safety, allowing you to try to cast anything to anything else. It allows the underlying bit pattern of the source type to be reinterpreted as the destination type. This is done by casting to a reference or pointer variable then 'interpreting' the latter.

struct MyClass { std::uint8_t char a, b, c, d };
std::uint32_t i = 12345;
MyClass &p = reinterpret_cast<MyClass &> i;
std::uint8_t u = p.c; // Read 1 byte from 'within' i (N.B.: endianness not guaranteed)

reinterpret_cast can be very dangerous unless you know what you are doing. Showing the potential danger of old C-style casts, in some situations, a C-style cast will 'fall back' to reinterpret_casting if it cannot find a safer option:

int i = 0;
void *v = 0;
int c = (int)v; // is valid
int d = static_cast<int>(v); // is not valid, different types
int e = reinterpret_cast<int>(v); // is valid, but very dangerous

const_cast

Lastly, we have const_cast<T>, which removes the constness of a variable, thus allowing the result to be passed to a non-const function, etc. Like reinterpret_cast, a const_cast must be done via a reference or pointer.



FYI, I believe Bjarne Stroustrup is quoted as saying that C-style casts are to be avoided and that you should use static_cast or dynamic_cast if at all possible.

Barne Stroustrup's C++ style FAQ

Take that advice for what you will. I'm far from being a C++ guru.



You should look at the article C++ Programming/Type Casting.

It contains a good description of all of the different cast types. The following taken from the above link:

const_cast

const_cast(expression) The const_cast<>() is used to add/remove const(ness) (or volatile-ness) of a variable.

static_cast

static_cast(expression) The static_cast<>() is used to cast between the integer types. 'e.g.' char->long, int->short etc.

Static cast is also used to cast pointers to related types, for example casting void* to the appropriate type.

dynamic_cast

Dynamic cast is used to convert pointers and references at run-time, generally for the purpose of casting a pointer or reference up or down an inheritance chain (inheritance hierarchy).

dynamic_cast(expression)

The target type must be a pointer or reference type, and the expression must evaluate to a pointer or reference. Dynamic cast works only when the type of object to which the expression refers is compatible with the target type and the base class has at least one virtual member function. If not, and the type of expression being cast is a pointer, NULL is returned, if a dynamic cast on a reference fails, a bad_cast exception is thrown. When it doesn't fail, dynamic cast returns a pointer or reference of the target type to the object to which expression referred.

reinterpret_cast

Reinterpret cast simply casts one type bitwise to another. Any pointer or integral type can be casted to any other with reinterpret cast, easily allowing for misuse. For instance, with reinterpret cast one might, unsafely, cast an integer pointer to a string pointer.

By : Thomas


This video can help you solving your question :)
By: admin