Arran Duff
Arran Duff

Reputation: 1474

What happens when you dynamic_cast between derived classes with the same base class?

I am trying to figure out what happens when you dynamic_cast from one derived class to another derived class. Why does the below code raise a segmentation fault? Note that I am not trying to use this code for anything. I merely want to understand what is happening.

It's also worth noting that the same code works using static_cast. I can't seem to find any documentation that goes into the finer details of what is happening here. Can somebody explain?

struct base 
{ 
    virtual void printing(){cout<<"base printing"<<endl;};
};
struct derived_1 :public base 
{ 
    virtual void printing(){cout<<"derived_1 printing"<<endl;};
};
struct derived_2 :public base 
{ 
    virtual void printing(){cout<<"derived_2 printing"<<endl;};
};

int main()
{
    base * b = new derived_2();
    derived_1 *d_1 = dynamic_cast<derived_1*>(b);

    // calling printing raises segmentation fault
    d_1->printing(); 
}

Upvotes: 1

Views: 1257

Answers (1)

andreee
andreee

Reputation: 4679

The cast to derived_1 will fail, because derived_2 is a base object but not a derived_1 object. Therefore, you cannot "side cast" to the desired pointer type.

Not that whenever dynamic_cast fails, it will return a nullptr (except for reference types). This eventually leads to the segmentation fault in your code (in general, I would suggest you always add a if (d_1 != nullptr) before using a dynamically casted object).

Update:

By the way, this is actually a good example for the necessity of dynamic_cast. Even though you could be tempted to use static_cast in your example and it would compile, you will be dealing with undefined behavior. Using static_cast will compile without hickups, but you would actually be working with a broken type. Assume derived_1::printing() accesses some variable derived_1::a, which does not exist in derived_2. By statically side-casting a derived_2 object (which doesn't have a) to a derived_1 object d_1, you would falsely assume d_1 to contain some valid a, which is not the case.

Example:

// ...
struct derived_1 :public base
{
    const int a = 123;
    void printing() override {cout<<"derived_1 printing " << endl;}
    void foo() { cout << "Foo using constant = " << a << endl; }
};

// ...
int main()
{
    base * b = new derived_2();
    derived_1 *d_1 = static_cast<derived_1*>(b);
    d_1->printing(); // Will call derived_2::printing(), which is not what you expect!
    d_1->foo();      // Won't show a = 123 but some nonesense (mostly 0),
                     // because a is not defined in derived_2.
}

Upvotes: 1

Related Questions