The Dark Knight The Dark Knight - 3 months ago 17
C++ Question

Dynamic_cast not showing the right object type

I spent a lot of time trying to figure out why my code displays "Derived3" after I run it and I cannot understand it at all. From what I have read here on many posts, dynamic_cast should somehow say whether a pointer (in this case b) is (in this case) Derived2 or not. However, it passed the condition and when it should print out the display() function from Derived2 class, it strangely displayes the one from the Derived3 class. I am just wondering why the program displays "Derived 3" instead of not showing anything, since b pointer is clearly not pointing to a Derived2 object.

#include <iostream>

using namespace std;

class Base
{
int b;
public:
virtual void display()
{
cout<<"Base"<<endl;
}
};

class Derived: virtual public Base{
public:
void display()
{
cout<<"Derived"<<endl;
}
};

class Derived2: virtual public Base{
public:
void display()
{
cout<<"Derived 2"<<endl;
}
};

class Derived3:public Derived,public Derived2{
public:
void display()
{
cout<<"Derived 3"<<endl;
}
};

int main()
{
Base *b = new Derived3();
Derived2 *aux = dynamic_cast<Derived2*>(b);
if(aux)
{
aux->display();
}

return 0;
}


However, after editing the code a little bit, it works as it should be.

#include <iostream>

using namespace std;

class Base
{
int b;
public:
virtual void display()
{
cout<<"Base"<<endl;
}
};

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

class Derived2: public Base{
public:
void display()
{
cout<<"Derived 2"<<endl;
}
};

class Derived3:public Base{
public:
void display()
{
cout<<"Derived 3"<<endl;
}
};

int main()
{
Base *b = new Derived3();
Derived2 *aux = dynamic_cast<Derived2*>(b);
if(aux)
{
aux->display();
}

return 0;
}

Answer Source

Inheritance is a "Is-a" relationship.

Every Derived is both a Derived and a Base. By that pattern, every Derived3 is a Derived3, a Derived2, a Derived and a Base at the same time.

It would thus not make sense for that cast to fail.

The output is then finally the result of a normal virtual function call on a Derived2*. This is no different than in the most trivial example of inheritance, like in this snippet:

#include <iostream>

struct A {
    virtual void fun() const {
        std::cout << 'A';
    }
};

struct B : A {
    void fun() const {
        std::cout << 'B';
    }
};

int main () {
    const A &a = B();
    a.fun();            // prints 'B'
}

If you have a pointer or reference to some base class, a virtual function call will resolve to the actual type of the object it is called on. In your case, that's a Derived2* pointing to a child-class of type Derived3, so the function is looked up in the latter.

Keep in mind that the dynamic_cast only changes the type of the pointer, not the type of the object it points to!