More Effective C++ | Item 2: Prefer C++-style casts Back to Item 1: Distinguish between pointers and references Continue to Item 3: Never treat arrays polymorphically Item 2: Prefer C++-style casts. Consider the lowly cast. Nearly as much a programming pariah as the goto, it nonetheless endures, because when worse comes to worst and push comes to shove, casts can be necessary. Casts are especially necessary when worse comes to worst and push comes to shove. Still, C-style casts are not all they might be. For one thing, they're rather crude beasts, letting you cast pretty much any type to pretty much any other type. It would be nice to be able to specify more precisely the purpose of each cast. There is a great difference, for example, between a cast that changes a pointer-to-const-object into a pointer-to-non-const-object (i.e., a cast that changes only the constness of an object) and a cast that changes a pointer-to-base-class-object into a pointer-to-derived-class-object (i.e., a cast that completely changes an object's type). Traditional C-style casts make no such distinctions. (This is hardly a surprise. C-style casts were designed for C, not C++.) A second problem with casts is that they are hard to find. Syntactically, casts consist of little more than a pair of parentheses and an identifier, and parentheses and identifiers are used everywhere in C++. This makes it tough to answer even the most basic cast-related questions, questions like, "Are any casts used in this program?" That's because human readers are likely to overlook casts, and tools like grep cannot distinguish them from non-cast constructs that are syntactically similar. C++ addresses the shortcomings of C-style casts by introducing four new cast operators, static_cast, const_cast, dynamic_cast, and reinterpret_cast. For most purposes, all you need to know about these operators is that what you are accustomed to writing like this, (type) expression you should now generally write like this: static_cast(expression) For example, suppose you'd like to cast an int to a double to force an expression involving ints to yield a floating point value. Using C-style casts, you could do it like this: int firstNumber, secondNumber; ... double result = ((double)firstNumber)/secondNumber; With the new casts, you'd write it this way: double result = static_cast(firstNumber)/secondNumber; Now there's a cast that's easy to see, both for humans and for programs. static_cast has basically the same power and meaning as the general-purpose C-style cast. It also has the same kind of restrictions. For example, you can't cast a struct into an int or a double into a pointer using static_cast any more than you can with a C-style cast. Furthermore, static_cast can't remove constness from an expression, because another new cast, const_cast, is designed specifically to do that. The other new C++ casts are used for more restricted purposes. const_cast is used to cast away the constness or volatileness of an expression. By using a const_cast, you emphasize (to both humans and compilers) that the only thing you want to change through the cast is the constness or volatileness of something. This meaning is enforced by compilers. If you try to employ const_cast for anything other than modifying the constness or volatileness of an expression, your cast will be rejected. Here are some examples: class Widget { ... }; class SpecialWidget: public Widget { ... }; void update(SpecialWidget *psw); SpecialWidget sw; // sw is a non-const object, const SpecialWidget& csw = sw; // but csw is a reference to // it as a const object update(&csw); // error! can't pass a const // SpecialWidget* to a function // taking a SpecialWidget* update(const_cast(&csw)); // fine, the constness of &csw is // explicitly cast away (and // csw and sw may now be // changed inside update) update((SpecialWidget*)&csw); // same as above, but using a // harder-to-recognize C-style cast Widget *pw = new SpecialWidget; update(pw); // error! pw's type is Widget*, but // update takes a SpecialWidget* update(const_cast(pw)); // error! const_cast can be used only // to affect constness or volatileness, // never to cast down the inheritance // hierarch By far the most common use of const_cast is to cast away the constness of an object. The second specialized type of cast, dynamic_cast, is used to perform safe casts down or across an inheritance hierarchy. That is, you use dynamic_cast to cast pointers or references to base class objects into pointers or references to derived or sibling base class objects in such a way that you can determine whether the casts succeeded.1 Failed casts are indicated by a null pointer (when casting pointers) or an exception (when casting references): Widget *pw; ... update(dynamic_cast(pw)); // fine, passes to update a pointer // to the SpecialWidget pw points to // if pw really points to one, // otherwise passes the null pointer void updateViaRef(SpecialWidget& rsw); updateViaRef(dynamic_cast(*pw)); // fine, passes to updateViaRef the // SpecialWidget pw points to if pw // really points to one, otherwise // throws an exception dynamic_casts are restricted to helping you navigate inheritance hierarchies. They cannot be applied to types lacking virtual functions (see also Item 24), nor can they cast away constness: int firstNumber, secondNumber; ... double result = dynamic_cast(firstNumber)/secondNumber; // error! no inheritance is involved const SpecialWidget sw; ... update(dynamic_cast(&sw)); // error! dynamic_cast can't cast // away constness If you want to perform a cast on a type where inheritance is not involved, you probably want a static_cast. To cast constness away, you always want a const_cast. The last of the four new casting forms is reinterpret_cast. This operator is used to perform type conversions whose result is nearly always implementation-defined. As a result, reinterpret_casts are rarely portable. The most common use of reinterpret_cast is to cast between function pointer types. For example, suppose you have an array of pointers to functions of a particular type: typedef void (*FuncPtr)(); // a FuncPtr is a pointer // to a function taking no // args and returning void FuncPtr funcPtrArray[10]; // funcPtrArray is an array // of 10 FuncPtrs Let us suppose you wish (for some unfathomable reason) to place a pointer to the following function into funcPtrArray: int doSomething(); You can't do what you want without a cast, because doSomething has the wrong type for funcPtrArray. The functions in funcPtrArray return void, but doSomething returns an int: funcPtrArray[0] = &doSomething; // error! type mismatch A reinterpret_cast lets you force compilers to see things your way: funcPtrArray[0] = // this compiles reinterpret_cast(&doSomething); Casting function pointers is not portable (C++ offers no guarantee that all function pointers are represented the same way), and in some cases such casts yield incorrect results (see Item 31), so you should avoid casting function pointers unless your back's to the wall and a knife's at your throat. A sharp knife. A very sharp knife. If your compilers lack support for the new casting forms, you can use traditional casts in place of static_cast, const_cast, and reinterpret_cast. Furthermore, you can use macros to approximate the new syntax: #define static_cast(TYPE,EXPR) ((TYPE)(EXPR)) #define const_cast(TYPE,EXPR) ((TYPE)(EXPR)) #define reinterpret_cast(TYPE,EXPR) ((TYPE)(EXPR)) You'd use the approximations like this: double result = static_cast(double, firstNumber)/secondNumber; update(const_cast(SpecialWidget*, &sw)); funcPtrArray[0] = reinterpret_cast(FuncPtr, &doSomething); These approximations won't be as safe as the real things, of course, but they will simplify the process of upgrading your code when your compilers support the new casts. There is no easy way to emulate the behavior of a dynamic_cast, but many libraries provide functions to perform safe inheritance-based casts for you. If you lack such functions and you must perform this type of cast, you can fall back on C-style casts for those, too, but then you forego the ability to tell if the casts fail. Needless to say, you can define a macro to look like dynamic_cast, just as you can for the other casts: #define dynamic_cast(TYPE,EXPR) (TYPE)(EXPR) Remember that this approximation is not performing a true dynamic_cast; there is no way to tell if the cast fails. I know, I know, the new casts are ugly and hard to type. If you find them too unpleasant to look at, take solace in the knowledge that C-style casts continue to be valid. However, what the new casts lack in beauty they make up for in precision of meaning and easy recognizability. Programs that use the new casts are easier to parse (both for humans and for tools), and they allow compilers to diagnose casting errors that would otherwise go undetected. These are powerful arguments for abandoning C-style casts, and there may also be a third: perhaps making casts ugly and hard to type is a good thing. Back to Item 1: Distinguish between pointers and references Continue to Item 3: Never treat arrays polymorphically 1 A second, unrelated use of dynamic_cast is to find the beginning of the memory occupied by an object. We explore that capability in Item 27. Return