tags:

views:

15935

answers:

10

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);
+1  A: 

dynamic_cast has runtime type checking and only works with references and pointers, whereas static_cast does not offer runtime type checking. For complete information, see the following MSDN link.

MSDN Link

JTA
+12  A: 

You should look at the following article: http://en.wikibooks.org/wiki/C%2B%2B_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.

Thomas
+41  A: 

Static Cast

static_cast doesn't do any run time checking of the types involved, which means that unless you know what you are doing, they could be very unsafe. It also 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.

It does not allow casts between fundamentally different types, such as a cast between a BaseA and BaseB if they are not related. This will result in a compile time error.

Dynamic Cast

dynamic_cast will do run time checking as well, and if the instance cannot be cast into another derived type, it will return a null pointer.

Examples

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 correct typed version of b

The problem comes in the following example:

B* b = new B();
D* d1 = static_cast<D*>b; // Invalid!
D* d2 = dynamic_cast<D*>b; // Valid, but d2 is now a null pointer

Now d1 will point to a data segment of type D*, but the actual data is B*, and will lead to memory issues and corruption. d2 on the other hand will be a null pointer and can be checked for and handled correctly.

Because dynamic_cast performs runtime type checking it is also slower.

EDIT:

Since dynamic_cast can incurr extra runtime, it can be turned off by instructing the compiler not to include Runtime Type Information.

There are also other cast operators.

Reinterpret Cast

This is the ultimate cast, which disregards all kind of type safety, allowing you to cast anything to anything else, basically reassigning the type information of the bit pattern.

int i = 12345;
MyClass* p = reinterpret_cast<MyClass*> i;

It is very dangerous unless you know what you are doing, and is basically the equivilant of C-cast. Like so;

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

And then we have the const_cast<> which removes the const-ness of a variable.

Mats Fredriksson
You forgot to add that this only works when activating RTTI. Without Runtime Type Information, dynamic_cast won't work.
Vincent Robert
First you don't have to use pointers with static_cast. And second static_cast does compile-time type checking. You can't cast anything to anything.dynamic_cast only allows to pointer or references as the destination type and will only succeed when the new type is in the inheritance chain.
Dusty Campbell
This answer could be improved if it included a description of what the classic cast method does.
Jeff
This answer is totally misleading on the safeness of static_cast<>. The explanation of dynamic_cast<> is technically accurate in the narrowest definitions. The explanation of reinterpret_cast<> is basic and no mention of static_cast<>. This answer needs a re-write.
Martin York
dynamic_cast example is downright wrong. D is private ly inherited. secondly, there is no virtual function in the classes; so, you can't use dynamic_cast between them. what GCC outputs: error: cannot dynamic_cast ‘b’ (of type ‘class B*’) to type ‘class D*’ (source type is not polymorphic)
Comptrol
It's absolutely puzzling to me how this has 33 votes, when these objections in the comments being there for ages, without being considered. Sorry, -1
Johannes Schaub - litb
dynamic_cast of a pointer will return 0 in error case, but dynamic_cast of a reference will throw an exception.
frunsi
+3  A: 

C-style casts conflate const_cast, static_cast, and reinterpret_cast.

I wish C++ didn't have C-style casts. C++ casts stand out properly (as they should; casts are normally indicative of doing something bad) and properly distinguish between the different kinds of conversion that casts perform. They also permit similar-looking functions to be written, e.g. boost::lexical_cast, which is quite nice from a consistency perspective.

DrPizza
+4  A: 

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 (cached in Windows Live search since the page doesn't seem to want to come up right now.

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

Jason Baker
+1  A: 

Also I recommend the Effective C++ books by Scott Meyers for details on casting.

horace
+3  A: 

avoid using C-Style cast.

C-Style cast is a mix of const and reinterpret cast and it's difficult to find-and-replace in your code. C++ application programmer should avoid c-style cast.

ugasoft
+3  A: 

Here's a good explanation of the issue.

Jason Baker
+78  A: 

static_cast

static_cast is used for cases where you basically want to reverse an implicit conversion, with a few restrictions and additions. static_cast performs no runtime checks. This should be used if you know that you refer to an object of a specific type, and thus a check would be unnecessary. Example:

void func(void *data) {
  // conversion from MyClass* -> void* is implicit
  MyClass *c = static_cast<MyClass*>(data);
  ...
}

int main() { MyClass c; start_thread(&func, &c).join(); }

In this example, you know that you passed a MyClass object, and thus there is no need for a runtime check to ensure this.

dynamic_cast

dynamic_cast is used for cases where you don't know what the dynamic type of the object is. You cannot use dynamic_cast if you downcast and the argument type is not polymorphic. An example

if(JumpStm *j = dynamic_cast<JumpStm*>(&stm)) {
  ...
} else if(ExprStm *e = dynamic_cast<ExprStm*>(&stm)) { 
  ...
}

dynamic_cast returns a null pointer if the object referred to doesn't contain the type casted to as a base class (when you cast to a reference, a bad_cast exception is thrown in that case).

The following code is not valid, because Base is not polymorphic (doesn't contain a virtual function):

struct Base { };
struct Derived : Base { };
int main() { 
  Derived d; Base *b = &d;
  dynamic_cast<Derived*>(b); // invalid
}

An "up-cast" is always valid with both static_cast and dynamic_cast, and also without any cast, as an "up-cast" is an implicit conversion.

Regular Cast

These casts are also called c-style cast. A c-style cast is basically identical to trying out a range of sequences of C++ casts, and taking the first c++ cast that works, without ever considering dynamic_cast. Needless to say that this is much more powerful as it combines all of const_cast, static_cast and reinterpret_cast, but it's also unsafe because it does not use dynamic_cast.

In addition, C-style casts not only allow you to do this, but also allow you to safely cast to a private base-class, while the "equivalent" static_cast sequence would give you a compile time error for that.

Some people prefer c-style casts because of their brevity. I use them for numeric casts only, and use the appropriate C++ casts when user defined types are involved, as they provide stricter checking.

Johannes Schaub - litb
+1 for technical accuracy, only 30 more votes to go.
Charles Bailey
thanks Charles :)
Johannes Schaub - litb
22 votes to go...
Matthieu M.
I almost upvoted, but there is one thing I have a problem with: casting within the inheritance hierarchy with reinterpret_cast is definitely not valid (if by valid you mean "not exhibiting undefined behavior". If you meant that it is well-formed, I apologize.).
avakar
@avakar, you are completely right. I think i wanted to write "dynamic_cast" instead of "reinterpret_cast". I fixed it, thanks!
Johannes Schaub - litb
Ah, that's better, +1 :)
avakar
+1 for many reasons,Including making this reach 36 :D
Madi D.