Faq: Why Does Dynamic_Cast Only Work If a Class Has at Least 1 Virtual Method

FAQ: Why does dynamic_cast only work if a class has at least 1 virtual method?

Because dynamic_cast can only downcast polymorphic types, so sayeth the Standard.

You can make your class polymoprphic by adding a virtual destructor to the base class. In fact, you probably should anyway (See Footnote). Else if you try to delete a B object through an A pointer, you'll evoke Undefined Behavior.

class A
{
public:
virtual ~A() {};
};

et voila!

Footnote

There are exceptions to the "rule" about needing a virtual destructor in polymorphic types.

One such exception is when using boost::shared_ptr as pointed out by Steve Jessop in the comments below. For more information about when you need a virtual destructor, read this Herb Sutter article.

FAQ: Why does dynamic_cast only work if a class has at least 1 virtual method?

Because dynamic_cast can only downcast polymorphic types, so sayeth the Standard.

You can make your class polymoprphic by adding a virtual destructor to the base class. In fact, you probably should anyway (See Footnote). Else if you try to delete a B object through an A pointer, you'll evoke Undefined Behavior.

class A
{
public:
virtual ~A() {};
};

et voila!

Footnote

There are exceptions to the "rule" about needing a virtual destructor in polymorphic types.

One such exception is when using boost::shared_ptr as pointed out by Steve Jessop in the comments below. For more information about when you need a virtual destructor, read this Herb Sutter article.

Why Base-to-Derived Dynamic Casting is Only Allowed for Polymorphic Classes

What is the reason for this limitation?

dynamic_cast is only supposed to succeed when the object is an instance of the target type.
Non-polymorphic classes don't contain any type information, so there is no way to tell whether this is the case; therefore, the cast cannot succeed.

Is it more 'safe' to have a pure virtual function in place of the normal virtual function in the base class?

Either is fine, as far as polymorphism is concerned. If the base class has at least one virtual function, then it is polymorphic, and so can be used with dynamic_cast. Whether it's pure or not only affects whether the base class can be instantiated.

(C++) should'nt this dynamic_cast retrieve the derived class

For dynamic_cast<> to work, the object needs to have a vtable. Otherwise, there is no indication within the object to which dynamic class it belongs.

A vtable is added to a C++ class if, and only if that class contains at least one virtual function.

So, add at least one virtual function to the class, and the dynamic cast should work.

Does dynamic_cast require virtual function?

Yes it does, as per the standard, dynamic_cast can only downcast polymorphic types (i.e. a type with at least one virtual function)

How does dynamic_cast work?

The most important thing about the dynamic cast is that it should be applied to a polymorphic type. Without that, dynamic cast works like a static cast.

What is a polymorphic type? Any class that has at least one virtual method or virtual destructor or virtual base class is polymorphic. Only those types have a virtual method table (VMT) in their data layout. Classes that do not have anything virtual do not have VMT's. The standard does not say how polymorphism and virtual methods should be implemented, yet all compilers, as far as I know, do this.

In your examples classes are not polymorphic. In my opinion, it would be better if compilers would issue an error when the dynamic cast is applied to a non-polymorphic type. Nevertheless, they do not do this. This adds to the confusion.

VMT pointers for all classes are different. This means that on the runtime looking at:

Animal* animal;

it is possible to know what the real class of the object is. Is it a Bird or a Dog or something else. Knowing the real type from the value of VMT, generated code can make an adjustment if this is needed.

Here is an example:

class Animal   { virtual ~Animal();   int m1; };
class Creature { virtual ~Creature(); int m2; };

class Bird : public Animal, Creature { };

Bird *bird = new Bird();
Creature *creature = dynamic_cast<Creature*>(bird);

Note that creature is not the first base class. This means that the pointer will be shifted to point to the right part of the object. Nevertheless, the following will still be working:

Animal *animal = dynamic_cast<Animal*>(creature);   // Case2.

because VMT of Creature when it is part of other class will not be the same to VMT of the object when it is used stand-alone:

Creature *creature1 = new Creature();

This distinction allows a proper implementation of a dynamic cast. In the example Case2 the pointer will be shifted back. I tested this. This works.

The reason why dynamic_cast doesn't work with non-polymorphic types

Because there is no way to implement dynamic_cast without some type information stored in the object for run-time use. And there are only two features of the language which need a run-time information on the object's type: virtual functions, and dynamic_cast.

If it was possible to use dynamic_cast to downcast non-polymorphic types, compliers would have to store run-time type information in every class type. This would go directly against the "only pay for what you use" philosophy of C++, and it would utterly break its compatibility with C and many external interfaces, hardware etc. There would be no standard-layout class types, basically. Or, alternatively, no class types where you could have full control of their layout.

Difference between static and dynamic cast

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()).

dynamic_cast and static_cast in C++

Here's a rundown on static_cast<> and dynamic_cast<> specifically as they pertain to pointers. This is just a 101-level rundown, it does not cover all the intricacies.

static_cast< Type* >(ptr)

This takes the pointer in ptr and tries to safely cast it to a pointer of type Type*. This cast is done at compile time. It will only perform the cast if the types are related. If the types are not related, you will get a compiler error. For example:

class B {};
class D : public B {};
class X {};

int main()
{
D* d = new D;
B* b = static_cast<B*>(d); // this works
X* x = static_cast<X*>(d); // ERROR - Won't compile
return 0;
}

dynamic_cast< Type* >(ptr)

This again tries to take the pointer in ptr and safely cast it to a pointer of type Type*. But this cast is executed at runtime, not compile time. Because this is a run-time cast, it is useful especially when combined with polymorphic classes. In fact, in certian cases the classes must be polymorphic in order for the cast to be legal.

Casts can go in one of two directions: from base to derived (B2D) or from derived to base (D2B). It's simple enough to see how D2B casts would work at runtime. Either ptr was derived from Type or it wasn't. In the case of D2B dynamic_cast<>s, the rules are simple. You can try to cast anything to anything else, and if ptr was in fact derived from Type, you'll get a Type* pointer back from dynamic_cast. Otherwise, you'll get a NULL pointer.

But B2D casts are a little more complicated. Consider the following code:

#include <iostream>
using namespace std;

class Base
{
public:
virtual void DoIt() = 0; // pure virtual
virtual ~Base() {};
};

class Foo : public Base
{
public:
virtual void DoIt() { cout << "Foo"; };
void FooIt() { cout << "Fooing It..."; }
};

class Bar : public Base
{
public :
virtual void DoIt() { cout << "Bar"; }
void BarIt() { cout << "baring It..."; }
};

Base* CreateRandom()
{
if( (rand()%2) == 0 )
return new Foo;
else
return new Bar;
}

int main()
{
for( int n = 0; n < 10; ++n )
{
Base* base = CreateRandom();

base->DoIt();

Bar* bar = (Bar*)base;
bar->BarIt();
}
return 0;
}

main() can't tell what kind of object CreateRandom() will return, so the C-style cast Bar* bar = (Bar*)base; is decidedly not type-safe. How could you fix this? One way would be to add a function like bool AreYouABar() const = 0; to the base class and return true from Bar and false from Foo. But there is another way: use dynamic_cast<>:

int main()
{
for( int n = 0; n < 10; ++n )
{
Base* base = CreateRandom();

base->DoIt();

Bar* bar = dynamic_cast<Bar*>(base);
Foo* foo = dynamic_cast<Foo*>(base);
if( bar )
bar->BarIt();
if( foo )
foo->FooIt();
}
return 0;

}

The casts execute at runtime, and work by querying the object (no need to worry about how for now), asking it if it the type we're looking for. If it is, dynamic_cast<Type*> returns a pointer; otherwise it returns NULL.

In order for this base-to-derived casting to work using dynamic_cast<>, Base, Foo and Bar must be what the Standard calls polymorphic types. In order to be a polymorphic type, your class must have at least one virtual function. If your classes are not polymorphic types, the base-to-derived use of dynamic_cast will not compile. Example:

class Base {};
class Der : public Base {};

int main()
{
Base* base = new Der;
Der* der = dynamic_cast<Der*>(base); // ERROR - Won't compile

return 0;
}

Adding a virtual function to base, such as a virtual dtor, will make both Base and Der polymorphic types:

class Base 
{
public:
virtual ~Base(){};
};
class Der : public Base {};

int main()
{
Base* base = new Der;
Der* der = dynamic_cast<Der*>(base); // OK

return 0;
}


Related Topics



Leave a reply



Submit