tags:

views:

69

answers:

3

For simplicity,

class Parent {}
class Child1 : Parent {}
class Child2 : Parent {}

Elsewhere, I created instances of Child1 and Child2 and store it in same vector under Parent:

// . . . in .h file, for example
vector<Parent> vector_of_parent;

// . . . in one particular method
Child1 c1; 
Child2 c2; 
vector_of_parent.push_back(c1);
vector_of_parent.push_back(c2);
// . . .

Then in another method which has access to vector_of_parent, I tried

 void doSomething(Parent& some_child) { 
 // wrapped in a try block somehow...
 Child1& c = dynamic_cast<Child1&> some_child;
 // do something if the cast is successful
 }

 void otherMethod() {
      doSomething(vector_of_parent.at(0)); // vector_of_parent.at(0) is a Child1
 }

Why is there a std:bad_cast when I call otherMethod()?

+6  A: 

When you say:

vector<Parent> vector_of_parent;

you create a vector of Parent - it cannot possibly contain Child objects. If you want a polymorphic C++ container, it must contain base class pointers. Your dynamic cast is failing because the things you apply it to are always Parent and never Child.

Also, it's not clear from your code, but in order to use dynamic_cast, your base class must contain at least one virtual function.

anon
A virtual destructor would be a good start :)
FredOverflow
I've always thought that for non-polymorphic types dynamic_cast acts like static cast. Am I wrong?
Basilevs
@Basilevs: For a dynamic_cast to be valid, the argument must be convertible to the required type by upcast (trivially safe), must already be the same type as required, or must be a polymorphic type.
Joe Gauterin
+7  A: 

Your std::vector is declared as std::vector<Parent>. It holds only instances of Parent - when you insert the Child1 and Child2 instances, they get sliced.

If you want to use a vector of polymorphic objects with a common base class of Parent, you need to use a container of pointers (or, for ease of lifetime and memory management, smart pointers).

Appropriate container types to consider include std::vector<Parent*>, std::vector<std::tr1::shared_ptr<Parent> > and boost::ptr_vector<Parent>.

I'd recommend against the std::vector<Parent*> unless you're very comfortable with manual memory management.


Also, you need to use public inheritance instead of private, and the base class must have a virtual destructor. I assume you left these out for brevity though.

Joe Gauterin
+1 for mentioning the object slicing.
ereOn
+3  A: 
vector<Parent> vector_of_parent;

You are creating a vector of Parent objects. Note that vector will always create a copy of the object passed. So when you do vector_of_parent.push_back(c1); a copy of c1 is created with a code like (for simplicity I am ignoring allocator) T* pObj = new T(c1);. Since here type of T is Parent , the copy created is of type Parent. So basically what happended was child objects is sliced to create parent object out of it. Now, if you try to dynamic_cast this Parent object to a Child type it will throw an exception.

Naveen