Person.Junkie
Person.Junkie

Reputation: 1886

Difference between static and dynamic cast

The class is polymorphic. Why do both print the same output?

class A
{
public:
    virtual void P(){ cout << "A" << endl; }

};
class B : public A
{
public:
    void P()override{
        cout << "B" << endl;
    }
    B(){ cout << "Created B" << endl; s = "Created by B"; }
    string s;
};

And main: Variant 1:

A* a = new B();    // Created B
B* b = static_cast<B*>(a);
b->P();    B
cout<<b->s<<endl;  // Created by B

And variant 2:

A* a = new B();
    B* b = dynamic_cast<B*>(a);
    if (b){
        b->P();
        cout << b->s << endl;  // Prints same
    }

Upvotes: 2

Views: 9348

Answers (2)

user3920237
user3920237

Reputation:

In this case, static_cast is semantically equivalent to dynamic_cast.

static_cast < new_type > ( expression )

2) If new_type is a pointer or reference to some class D and the type of expression is a pointer or reference to its non-virtual base B, static_cast performs a downcast. Such static_cast makes no runtime checks to ensure that the object's runtime type is actually D, and may only be used safely if this precondition is guaranteed by other means, such as when implementing static polymorphism. Safe downcast may be done with dynamic_cast.

dynamic_cast < new_type > ( expression )

5) If expression is a pointer or reference to a polymorphic type Base, and new_type is a pointer or reference to the type Derived a run-time check is performed:

a) The most derived object pointed/identified by expression is examined. If, in that object, expression points/refers to a public base of Derived, and if only one subobject of Derived type is derived from the subobject pointed/identified by expression, then the result of the cast points/refers to that Derived subobject. (This is known as a "downcast".)

[...]

c) Otherwise, the runtime check fails. If the dynamic_cast is used on pointers, the null pointer value of type new_type is returned. If it was used on references, the exception std::bad_cast is thrown.

The last clause is what makes dynamic_cast safer, as you can check if the cast was unsuccessful:

Base* b1 = new Base;
if(Derived* d = dynamic_cast<Derived*>(b1))
{
    std::cout << "downcast from b1 to d successful\n";
    d->name(); // safe to call
}

Upvotes: 1

John Zwinck
John Zwinck

Reputation: 249123

Both of your examples will do the same thing, and that's fine. Try with this instead:

A* a = new A();

In this case, the static_cast will "succeed" (though it is undefined behavior), whereas the dynamic_cast will "fail" (by returning nullptr, which you already check for).

Your original examples don't show anything interesting because they both succeed and are valid casts. The difference with dynamic_cast is that it lets you detect invalid casts.

If you want to know how dynamic_cast does this, read about RTTI, Run Time Type Information. This is some additional bookkeeping that C++ does in certain cases to inspect the type of an object (it's important for this and also if you use typeid()).

Upvotes: 8

Related Questions