Search code examples
c++polymorphismc++17dynamic-castnullptr

Why is the dynamic_cast allowed to yield a null-pointer for polymorphic classes when the destination pointer is not of the type of a base class?


Consider the following program

#include <iostream>
#include <iomanip>

struct A
{
};

struct C
{
};

int main()
{
    C *pc = nullptr;

    A *pa1 = dynamic_cast<A *>( pc );

    std::cout << "pa1 == nullptr is " << std::boolalpha << ( pa1 == nullptr ) << '\n';

    A *pa2 = pc;

    std::cout << "pa2 == nullptr is " << std::boolalpha << ( pa2 == nullptr ) << '\n';
}

For the both pointer declarations, pa1 and pa2, the compiler reports an error that such an initialization is not allowed.

For example the clang HEAD 10.0.0 compiler issues the following errors.

prog.cc:19:14: error: 'C' is not polymorphic
    A *pa1 = dynamic_cast<A *>( pc );
             ^                  ~~
prog.cc:23:8: error: cannot initialize a variable of type 'A *' with an lvalue of type 'C *'
    A *pa2 = pc;
       ^     ~~
2 errors generated.

Now let's make the class C a polymorphic class.

#include <iostream>
#include <iomanip>

struct A
{
};

struct C
{
    virtual ~C() = default; 
};


int main()
{
    C *pc = nullptr;

    A *pa1 = dynamic_cast<A *>( pc );

    std::cout << "pa1 == nullptr is " << std::boolalpha << ( pa1 == nullptr ) << '\n';

    A *pa2 = pc;

    std::cout << "pa2 == nullptr is " << std::boolalpha << ( pa2 == nullptr ) << '\n';
}

And only the second declaration produces an error. The dynamic_cast works.

rog.cc:22:8: error: cannot initialize a variable of type 'A *' with an lvalue of type 'C *'
    A *pa2 = pc;
       ^     ~~
1 error generated.

What is the reason of that such a conversion of pointers for the dynamic_cast is allowed?


Solution

  • What is the reason of that such a conversion of pointers for the dynamic_cast is allowed?

    Because dynamic_cast runs at run time, and it's too late to issue a compiler error by then.

    If the conversion fails, dynamic_cast returns nullptr. You need to check for that and then handle that if needed.