The C programming language's syntax for typecasting is very concise: Simply precede an expression with the name of another type in parentheses, and presto! it's the other type.

Now this syntax works in C++, but it has so many problems that the technique has been "deprecated" by the C++ Standard. That is, don't use it in new code.

Watch those fingers! or, Don't do the crime if you can't do the time

The easiest problem to explain. You're taking one of the language's premier features, type safety, and tossing it out the window. "But there are times I really, really need to do this!", you say. And you're right; there are. But they're rare (or should be1), and you really need to think about the consequences of violating type safety before doing it. The easiness of typecasting encourages its use for many problems that are better solved by thinking out their design ahead of time. It's like operating a table saw without a blade guard. Except that violating type safety can lead to far, far more severe consequences than the loss of a couple of fingers.

What's this thing do, anyway?

Another big problem is that casting is used for a whole bunch of tasks that mean different things (i.e. they're semantically different) and had different effects. It all depends upon the type you're casting from and the type you're casting to:

  • Changing a value's representation. C and C++ are full of "standard conversions" that change one type into another. Some are done implicitly, but for others, you have to use a casting operator. Let's say we want to find the integer part of a floating point value. We can say:
    float f = 3.14159;
    int i = (int)f; // i now equals 3
    
    or, convert an integer into an enumerator:
    enum color {red, green, blue};
    color c = (color)2; // MAYBE color == blue now
    
    The internal physical representation of the objects changes when we do this. Sometimes bits are simply added or subtracted; other times, as in the float-to-int conversion, the object is completely rearranged.
     
  • Casting away constness. Let's say you want to assign to a const object. This of course goes against the definition of constness, but sometimes it's necessary (e.g. Windows API calls). And so you can say:
    const int i = 3;
    (int) i = i + 1; // i == 4 now, despite being const
    
    We're making a promise in one part of the code and breaking it in another!
     
  • Converting an object of one class type into an object that's a derived class type. This is a form of typecasting that you don't get in C. It's safe as long as the object is really of the derived type:
    class Base {
    public:
    virtual ~base() {}
    };
    class Derived: public Base { };
    Base *b = new Derived;
    Derived *d = (Derived *)b;
    
    There's an analogue in C where you cast a struct object into one of its members:
    struct Baseoid {int i' };
    struct Derivedoid { Baseoid b; int j; };
    
    Baseoid *b = (Baseoid *) malloc (sizeof(Derivedoid) );
    Derivedoid *d = (Derivedoid*) b;
    
    b.i = 3;
    d.j = d.b.i; // d.j now == 3
    
  • Pretending an object is of one type when it's really another type, the kitchen sink of casting. You can convert a pointer into a struct, a function pointer into an integer, anything that isn't well defined in the compiler. This type of casting is like using the different members of a union:
    union { float f;
            int i;
          } u;
    u.f = 3.14159; // I Can guarantee that u.i != 3;
    
    or even
    float f = (float) u;  // f == 3.14159;
    
    The compiler has no way to convert betwen the two types, and simply interprets the same bits as if it were the other type.
These all become necessary at times (poor, poor Windows programmer) but they are all deadly dangerous.

Well, then, now what?

Bjarne Stroustrup, the inventor of C++, realized the problems of casting in the late 1980's. The second edition of his book The C++ Programming Language actually described macros for run-time type identification and safer typecasting. These were later incorporated into Standard C++, and appear in the third edition of his book. C++ now has separate operators for the four semantic categories of typecasting:

  • static_castfor well-defined representation conversions, such as builtin conversions, converting derived types to base types, and class type conversion operators.
    enum color {red, green, blue};
    color c = static_cast<color>(2); // MAYBE color == blue now
    
  • const_cast for casting away constness:
    const int i = 3;
    const_cast<int>(i) = i + 1; // i == 4 now, despite being const
    
  • dynamic_cast for converting base class objects into derived class objects,
    Derived *d = dynamic_cast<Derived *>(b);
    
  • and finally reinterpret_cast for everything else:
    float f = reinterpret_cast<float>(u); 
    

Ugly? Sure! That's the point. Aesthetic justice, I say. You're doing something ugly here, and it has to be labeled with a big ugly red flashing neon sign.


1Pity us poor souls who must program to the Microsoft Windows API.