25

This does not compile in C++:

class A
{
};

class B : public A
{
};

...

A *a = new B();
B *b = dynamic_cast<B*>(a);
John Dibling
  • 99,718
  • 31
  • 186
  • 324
Filip Frącz
  • 5,881
  • 11
  • 45
  • 67
  • 4
    I FAQ-ified this question. The answer is brief but I think pretty solid. If anyone thinks this should not be FAQed, let me know in the comments. – John Dibling Nov 20 '10 at 15:40

3 Answers3

35

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.

Community
  • 1
  • 1
John Dibling
  • 99,718
  • 31
  • 186
  • 324
  • 1
    "you'll leak resources." -> "you'll get UB." – GManNickG Nov 19 '10 at 16:54
  • 2
    Rule 50: Make base class destructors public and virtual, or protected and nonvirtual (http://www.gotw.ca/publications/c++cs.htm). Sometimes you don't want polymorphism. Just sayin'. – gregg Nov 19 '10 at 17:31
  • @gregg: indeed true, but OP needs polymorphism here – John Dibling Nov 19 '10 at 17:34
  • And sometimes you need polymorphism, but you don't need `delete` to be polymorphic. – Steve Jessop Nov 19 '10 at 18:20
  • 2
    @John: (1) if the pointer is stored directly with `shared_ptr ptr(new derived)`. (2) if there are users of the object that aren't responsible for its memory management, and use it through a base class, whereas whoever is responsible for memory management uses the derived class. Basically the same situations that you might ever have a class which has some virtual functions and some non-virtual functions, but in this case the non-virtual "function" is the operation of deleting it. Not all users of all objects need to delete the object as part of their API to it. – Steve Jessop Nov 20 '10 at 00:09
  • @Steve: in (1) you'd still need a virtual dtor. the shared_ptr is going to delete through a base*. (2) true, if the delete-er deletes through a derived ptr, it doesnt need a virtual destructor. Can't think of when this would happen, but ok. – John Dibling Nov 20 '10 at 06:24
  • 3
    @John: in (1) it's going to delete through `derived*`. Check the template constructor of `shared_ptr`. (2) depends on your programming style - if any access to an object always comes with lifecycle management, then all interfaces must include `delete`, and so polymorphic interfaces need virtual destructors. If there's a type of objects that you see without owning, then protected non-virtual destructor can be appropriate even if there are virtual functions. – Steve Jessop Nov 20 '10 at 14:54
  • 2
    You could have a virtual visitor interface, for example, and the loop doing the visiting wouldn't delete the visitor, so `delete` isn't part of the visitor interface. Normally in C++ you'd use templates for a visitor, but not always. – Steve Jessop Nov 20 '10 at 15:08
  • @Steve: (1) Aha, I did not know this! Kinda cool. +1 for the key learnings! – John Dibling Nov 20 '10 at 15:34
  • 1
    @John: Better link to this for UB: http://stackoverflow.com/questions/2397984/undefined-unspecified-and-implementation-defined-behavior – sbi Nov 20 '10 at 15:54
  • @sbi: that is a much better link that the one I have been using for UB – John Dibling Nov 20 '10 at 15:55
  • @John: 90secs searching [the list of FAQs](http://stackoverflow.com/questions/tagged/c%2b%2b-faq)! `` – sbi Nov 20 '10 at 15:59
  • @sbi: well, that's how I came up with the link I *was* using. no worries, now I'm using the new, shiny link. it's much better – John Dibling Nov 20 '10 at 16:02
13

As the other stated: The standard says so.

So why does the standard says so?

Because if the type isn't polymorphic it may (or is? Question to the standard gurus) be a plain type. And for plain types there are many assumptions coming from the C backwards compatibility. One of those is that the type only consists of it's members as the developer declared + necessary alignment bytes. So there cannot be any extra (hidden) fields. So there is no way to store in the memory space conserved by A the information that it really is a B.

This is only possible when it is polymorphic as then it is allowed to add such hidden stuff. (In most implementations this is done via the vtable).

mmmmmmmm
  • 15,269
  • 2
  • 30
  • 55
  • This is the famous "Don't pay for what you don't use" axiom: If you don't need run-time polymorphism, you don't get it. There is no virtual table ergo no late type RTTI ergo no `dynamic_cast`. – Paul Michalik Mar 26 '11 at 10:54
9

From 5.2.7 (Dynamic cast) :

The result of the expression dynamic_cast<T>(v) is the result of converting the expression v to type T.

[ ... multiple lines which refer to other cases ... ]

Otherwise v shall be a pointer to or an lvalue of a polymorphic type (10.3).

From 10.3 (Virtual functions) :

A class that declares or inherits a virtual function is called a polymorphic class.

icecrime
  • 74,451
  • 13
  • 99
  • 111