2010-06-08 15 views
1

Для простотыstd :: bad_cast от родителя к ребенку?

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

В другом месте я создал экземпляры ребенка1 и ребенка2 и хранить его в том же векторе под Родитель:

// . . . 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); 
// . . . 

Тогда в другом методе, который имеет доступ к vector_of_parent, я попытался

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 
} 

Почему существует std: bad_cast, когда я вызываю otherMethod()?

+1

Вы имеете в виду 'Child c1;' вместо 'Child c1();'? – kennytm

+0

да; будет делать изменения – polyglot

ответ

7

Ваш std::vector указан как std::vector<Parent>. Он содержит только экземпляры Parent - при вставке экземпляров Child1 и Child2 они получают sliced.

Если вы хотите использовать вектор полиморфных объектов с общим базовым классом Parent, вам необходимо использовать контейнер указателей (или, для удобства жизни и управления памятью, интеллектуальные указатели).

Соответствующие типы контейнеров для рассмотрения включают std::vector<Parent*>, std::vector<std::tr1::shared_ptr<Parent> > и boost::ptr_vector<Parent>.

Я бы рекомендовал против std::vector<Parent*>, если вам не очень удобно управлять памятью вручную.


Кроме того, вы должны использовать открытое наследование вместо частной, и базовый класс должен иметь виртуальный деструктор. Я предполагаю, что вы оставили их для краткости.

+1

+1 для упоминания обрезки объекта. – ereOn

6

Когда вы говорите:

vector<Parent> vector_of_parent; 

создать вектор Родитель - это не может содержать дочерние объекты. Если вам нужен полиморфный контейнер C++, он должен содержать указатели базового класса. Ваш динамический бросок терпит неудачу, потому что все, к чему вы его применяете, всегда является родительским и никогда не Child.

Кроме того, это не ясно из вашего кода, но для использования dynamic_cast ваш базовый класс должен содержать хотя бы одну виртуальную функцию.

+0

Виртуальный деструктор будет хорошим началом :) – fredoverflow

+1

Я всегда считал, что для неполиморфных типов dynamic_cast действует как статический приведение. Я ошибаюсь? – Basilevs

+0

@Basilevs: для того, чтобы dynamic_cast был действительным, аргумент должен быть преобразован в требуемый тип с помощью upcast (тривиально безопасный), должен быть того же типа, который требуется, или должен быть полиморфным. –

3
vector<Parent> vector_of_parent; 

Вы создаете вектор Parent объектов. Обратите внимание, что вектор всегда будет создавать копию переданного объекта. Поэтому, когда вы делаете vector_of_parent.push_back(c1);, копия c1 создается с помощью кода (для простоты я игнорирую распределитель) T* pObj = new T(c1);. Поскольку здесь тип T равен Parent, созданная копия имеет тип Parent. Таким образом, в основном то, что произошло, было дочерним объектом, нарезанным, чтобы создать из него родительский объект. Теперь, если вы попробуете dynamic_cast, этот объект Parent будет иметь значение Child, он выдает исключение.

Смежные вопросы