1

I was playing with dynamic_cast to understand its usage and came up with the code provided below. I used to believe dynamic_cast<D*>(B*) succeeds if and only if:

  • B is a polymorphic type i.e. it has a virtual function AND
  • D is derived from B

But in the code below Base and NonDerived classes are not related in above fashion still the dynamic_cast<NonDerived*>(Base*) succeeds. I was expecting it to fail and return a NULL instead. Which C++ rule is kicking in here?

I'm using a C++11 conformant compiler.

#include <iostream>

class Base {
    public:
        virtual ~Base() = default;
};

class Derived: public Base {
    public:
        void DerivedFun(){
            std::cout << "Derived" << std::endl;
        }
};

class NonDerived{
    public:
        void NonDerivedFun(){
            std::cout << "NonDerived" << std::endl;
        }
};

int main(){
    Base *pb = new Derived();

    Derived *pd = dynamic_cast<Derived*>(pb); // Expected this to succeed and it did
    pd->DerivedFun(); // Prints "Derived" as expected

    NonDerived *pn = dynamic_cast<NonDerived*>(pb); // Expected it to fail but it succeeded?
    pn->NonDerivedFun(); // Prints "NonDerived", expected this to throw some null pointer exception!!

    delete pb;
    return 0;
}
MasterJEET
  • 349
  • 3
  • 14

1 Answers1

2

pn->NonDerivedFun(); // Prints "NonDerived", expected this to throw some null pointer exception!!

There is no such thing as a "null pointer exception" when dereferencing a null pointer. It's undefined behavior to do so. To avoid it in this case, you must check if the dynamic_cast succeeded or not:

if (pn != nullptr) {
    pn->NonDerivedFun();
}
Nikos C.
  • 50,738
  • 9
  • 71
  • 96
  • So my understanding of `dynamic_cast` is correct but I don't fully understand 'null pointer' and its behavior? – MasterJEET Mar 20 '20 at 05:07
  • 3
    @MasterJEET I'd say you don't fully understand undefined behavior (commonly abbreviated as "UB"). Yes, `dynamic_cast` returns null just as you expected. But dereferencing a null pointer results in UB. – Nikos C. Mar 20 '20 at 05:11
  • 1
    @MasterJEET Correct. In your code snippet [`pn` is null](http://coliru.stacked-crooked.com/a/9f9beb0d1a3259df). The behavior of your program when calling `pn->NonDerivedFun()` is therefore undefined. Anything at all can happen. In this case, the call "works", likely because `NonDerived::NonDerivedFun` doesn't read or write any data from the object it's called on, but that behavior is not guaranteed and may be different from compiler to compiler or program to program. – Miles Budnek Mar 20 '20 at 05:12