Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

`dynamic_cast` from Base to Derived

Yes, I know that downcast using dynamic_cast can't compile if the Base is not polymorphic, but my problem is not about this.

class Base {
    public:
        virtual void bar()
        {
            cout << "bar\n";
        }
};

class Derived: public Base {
    public:
        void foo()
        {
            cout << "foo\n";
        }
};

int main()
{
    Base *pb;
    Derived *pd;

    pb = new Derived;  //Base* points to a Derived object
    pd = dynamic_cast<Derived*>(pb); 
    pd->foo();  //outputs foo

    pb = new Base;  //Base* points to a Base object
    pd = dynamic_cast<Derived*>(pb);  
    pd->foo();  //outputs foo, too. Why?
}

I thought when pb = new Derived;, pb actually points to a Derived object lies in heap. After pd = dynamic_cast<Derived*>(pb);, pd also points to that Derived object, so pd->foo() should be OK.

But when pb = new Base;, what pb points to is a Base object in heap, then after pd = dynamic_cast<Derived*>(pb);, how could pd->foo() works? Did dynamic_cast turn the Base object in heap into a Derived object?

like image 560
Alcott Avatar asked Apr 02 '12 09:04

Alcott


People also ask

What does dynamic_cast return in C++?

[edit] SyntaxIf the cast is successful, dynamic_cast returns a value of type new-type. If the cast fails and new-type is a pointer type, it returns a null pointer of that type. If the cast fails and new-type is a reference type, it throws an exception that matches a handler of type std::bad_cast.

How dynamic_cast is implemented in compiler?

Consider this simple hierarchy: class Base { public: virtual ~Base() { } }; class Derived : public Base { }; Trying to downcast Base* p to Derived* is possible using dynamic_cast<Derived*>(p) . I used to think dynamic_cast works by comparing the vtable pointer in p to the one in a Derived object.

What is the use of dynamic_cast in C++?

The dynamic_cast operator ensures that if you convert a pointer to class A to a pointer to class B , the object of type A pointed to by the former belongs to an object of type B or a class derived from B as a base class subobject.

What is the difference between Static_cast and dynamic_cast?

static_cast − This is used for the normal/ordinary type conversion. This is also the cast responsible for implicit type coersion and can also be called explicitly. You should use it in cases like converting float to int, char to int, etc. dynamic_cast −This cast is used for handling polymorphism.


2 Answers

You're running into undefined behavior. You should check the return type of dynamic_cast.

pd = dynamic_cast<Derived*>(pb);  

This returns null, and you call a function on a NULL pointer. Anything can happen.

like image 63
Luchian Grigore Avatar answered Sep 19 '22 10:09

Luchian Grigore


In C++, each instance of a class has its own version of datatypes, but all classes share the same function in memory (other than for inline functions). In your case, when you say something like:

pd->foo();

You are essentially calling Derived::foo, which is a function in memory and the compiler knows where it is. The thing is, it is not dependent on pd at all. However, if you had something like this:

class Derived : public Base {
    private:
        int a;

    public:
        Derived() { a = 100; }

        void foo() {
            std::cout<<a<<std::endl;
        }
 };

Then, pd->foo() will cause a Segmentation fault. Here, your dynamic cast has failed and when Derived::foo is called, it is passed 0 as the this object. It was fine in the previous case, as the this object was never used. However, in the second case, it is used and hence, causes a Segmentation fault.

like image 43
Rohan Prabhu Avatar answered Sep 20 '22 10:09

Rohan Prabhu