25

Scott Meyer in his book Effective C++ says 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.

Failed casts are indicated by a null pointer (when casting pointers) or an exception (when casting references).

I would like to get two code snippet showing the failed cast in the case of casting pointer and casting reference can be indicated.

nitin_cherian
  • 6,405
  • 21
  • 76
  • 127

3 Answers3

45

For pointers, it's a simple null check:

A* a = new A();
B* b = dynamic_cast<B*>(a);

if (b == NULL)
{
    // Cast failed
}

For references, you can catch:

try {
    SomeType &item = dynamic_cast<SomeType&>(obj);
}
catch(const std::bad_cast& e) {
    // Cast failed
}
zdan
  • 28,667
  • 7
  • 60
  • 71
Reed Copsey
  • 554,122
  • 78
  • 1,158
  • 1,373
  • @LinuxPenseur The check is assuming that "a" has a valid value. You'd have to check that first (for the allocation). The dynamic_cast check is checking whether A can safely be cast to "B" - so the check is against `b` for `NULL` - ie: b is null and a is not null. – Reed Copsey Jul 16 '12 at 18:28
  • @ReedCopsey : What is meant my `safe cast`. In which situation can b become NULL ? – nitin_cherian Jul 16 '12 at 18:30
  • 1
    `dynamic_cast` is used when a class is polymorphic (has `virtual` function) and it does run-time checks, returning a `NULL`pointer. Using `dynamic_cast` you are telling it to doexactly what you want instead of C-Style conversions where it tries various type of conversions. `dynamic_cast` is also used when you don't know the object to be converted, instead of `static_cast` that is used for non-polymoprhic classes and where both types on the conversion are known – Vinicius Horta Jul 16 '12 at 18:31
  • @ViniciusHorta : I did not mean to see a text book definition which is not at all what i asked for – nitin_cherian Jul 16 '12 at 18:34
  • 2
    @LinuxPenseur: `new()` doesn't necessarily return a null pointer on fail, you may need to check for an exception here also. `b` will become `NULL` if `a` is not an instance of `B`. – πάντα ῥεῖ Jul 16 '12 at 18:37
  • @g-makulik: The normal version of `new` won't return a null pointer ever -- it'll either return a valid pointer, or throw an exception. To get a null pointer on failure, you use `new(nothrow) whatever;` – Jerry Coffin Jul 16 '12 at 18:47
  • Please forgive a newbie question, but is `if (b)` equivalent to `if (b == NULL)`? – Attacktive Mar 22 '16 at 05:13
  • 1
    @Suzi it'd be the same as != NULL – Reed Copsey Mar 22 '16 at 05:15
5

Based on the OP's comment (" I do not understand how casts could fail as mentioned by Scott."), the real question here is really something like: "how could a dynamic_cast fail?"

The time it would fail is when the target type does not match the dynamic type of the object. For a simple example:

struct A {
   virtual ~A() {}
};

class B : public A {};

int main() { 
    A *a = new A;

    B *b = dynamic_cast<B *>(a);    // should fail
    if (b == NULL)
        std::cout << "First cast failed.\n";

    A *c = new B;
    b = dynamic_cast<B *>(c);       // should succeed
    if (b == NULL)
        std::cout << "Second cast failed.\n";
    return 0;
}

Here although a could point to an object of type B, it actually does point to an object of type A. When we try to do a dynamic_cast to get it to point to a B, that fails. In the second attempt, we again have a pointer that not only could but does point to an object of type B. Since it does, the dynamic_cast to B * succeeds in this case.

The basic situation doesn't change (much) for the reference case, just a, b and c become references instead of pointers, and we note the failure by catching an exception (which @ReedCopsey has already demonstrated well enough that I don't think I have anything new to add).

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
5

Here's a complete example that shows how dynamic_cast can fail to produce a pointer.

class A
{
public:
    virtual void Foo();
};

class B: public A
{
};

class C: public A
{
};

void test()
{
    A a;
    B b;
    A* pA = &b;
    B* pB = dynamic_cast<B*>(pA);  // this works OK, returns the expected pointer
    C* pC = dynamic_cast<C*>(pA);  // this returns NULL because B isn't a C
}

In the real world you'll be trying to cast pointers that weren't so straightforwardly created, perhaps they come from a vector for example.

Mark Ransom
  • 299,747
  • 42
  • 398
  • 622