Previous section   Next section

Imperfect C++ Practical Solutions for Real-Life Programming
By Matthew Wilson
Table of Contents
Chapter 19.  Casts


19.2. Casting in C++

Where implicit conversion is not sufficient, we may find it necessary to explicitly direct the compiler as to what conversion to apply (not that it is guaranteed to listen, of course). Sometimes, all that is needed is to provide a placeholder variable of an intermediate type, as in Listing 19.1.

Listing 19.1.


class A


{};





class B


  : public A


{};





class C


  : public A


{};





class D


  : public B


  , public C


{};





D *d = new D();


A *a = d;    // Error. Ambiguous conversion


B *b = d;    // first step (D* => B*) ok


A *a2 = b;   // second step (B* => A*) ok



The alternative to this is to use a cast. In C, you have the choice of the C-style cast only, which is a brute-force mechanism, to say the least.



A *a = (B*)d;  // hmm ...



If we subsequently changed the definition of D such that it no longer inherited from B, this code would still compile. Core dump, here we come!

C++ provides four cast operators [Stro1997] which practitioners are encouraged to use in preference to the C-style cast. These cast operators—static_cast, const_cast, dynamic_cast, and reinterpret_cast—present a separation of the casting functionalities provided by the traditional C-style cast, and are deliberately [Stro1994] strict about how they may be used.[2] The previous code could now be written as:

[2] If Asimov had been a C++ programmer, his robots would presumably observe the law(s) and use the C++ casts. I suspect the C-style case would be the favorite instrument of Iain Banks's Culture's much more autonomous Attitude Adjuster, or one of its brethren.



A *a = static_cast<B*>(d);  // ... much better!



This will correctly compile and translate the D* to A* for the original class relationship. Were the inheritance relationship between B and D severed, however, this would fail to compile, and we avoid finding out about our mistaken conversion at run time. The code demonstrates the syntax of the casts, which is cast-name<target-type>(operand). The syntax is eminently clear, and the uniformity is helpful: the cast, if successful, returns a view of type target-type on operand. One thing to remember as we develop the ideas in this section is that dynamic_cast can throw exceptions (std::bad_cast in fact) if a cast for a reference type fails.

There are obviously many more features and significant aspects to the C++ cast operators, which you can read about in most good C++ sources [Dewh2003, Meye1996, Meye1998, Sutt2000, Stro1997]. For the moment we'll consider the case made for their being preferred in good quality code, and move on, though we touch on them again regularly.


      Previous section   Next section