#include <iostream>
#include <list>
using namespace std;
//первый базовый классclass A
{
public:
void foo1() { cout << "A::foo1" << endl; }
};
//второй абстрактный базовый классclass B
{
public:
virtual void foo2() = 0;
};
//два производных классаclass C1: public A, public B
{
public:
void foo2() { cout << "C1::foo2" << endl; }
};
class C2: public A, public B
{
public:
void foo2() { cout << "C2::foo2" << endl; }
};
//используем следующим образомint main()
{
list<A*> lst;
lst.push_back(new C1());
lst.push_back(new C2());
for(list<A*>::iterator it = lst.begin(); it != lst.end(); ++it)
{
B* b = (B*)(*it);
b->foo2();// здесь падает
}
//...return 0;
}
На выделенном фрагменте программа падает. Если же делать так:
class C1: public A, virtualpublic B
{
public:
void foo2() { cout << "C1::foo2" << endl; }
};
class C2: public A, virtualpublic B
{
public:
void foo2() { cout << "C2::foo2" << endl; }
};
то все нормально отрабатывает. Что за поведение такое и правомерно ли указанное решение проблемы ? Может кто-нибудь прокомментировать
Проблема в том, что простой каст на B* не работает из-за расположения объектов в памяти. С-cast об этом ничего не знает. Надо делать static_ или dynamic_cast. Можно обойтись cast-om на B*... однако не работает ибо A* к B* не приводится. Поэтому надо сделать следующее:
B* b = static_cast<C1*>(*it);
Хотя тоже не элегантно, но работать уже будет.
И вот вы видите — все недостатки множественного наследования.
_DA>Используй dynamic_cast вместо этого преобразования.
Не пойдет. Преобразовать из A* в B* неизвестно как. Я думаю, что правильнее всего будет завести промежуточный тип:
class A
{
public:
void foo1() { cout << "A::foo1" << endl; }
};
//второй абстрактный базовый классclass B
{
public:
virtual void foo2() = 0;
};
class C: public A, public B
{
};
//два производных классаclass C1: public C
{
public:
void foo2() { cout << "C1::foo2" << endl; }
};
class C2: public C
{
public:
void foo2() { cout << "C2::foo2" << endl; }
};
Здравствуйте, avitya, Вы писали:
A>И вот вы видите — все недостатки множественного наследования.
Не, бери глюбже! И вот мы все лицезреем недостатки НТП. Ведь когда главным и единственным орудием труда были лапы и хвост такой проблемы возникнуть просто не могло бы!
Здравствуйте, Leshi, Вы писали:
L>Не пойдет. Преобразовать из A* в B* неизвестно как. Я думаю, что правильнее всего будет завести промежуточный тип:
L>Вот тогда можно будет dynamic_cast использовать.
Почему не пойдет — у меня в контейнере гарантировано будут храниться C1 или C2. А dynamic_cast может использоваться для cross cast-инга. В MSDN-е:
A A
| |
B C D
| _ | _ |
|
E
The dynamic_cast operator can also be used to perform a “cross cast.” Using the same class hierarchy, it is possible to cast a pointer, for example, from the B subobject to the D subobject, as long as the complete object is of type E.
Я сам до этого старался обходить множественное наследование — а здесь не получилось, вот и напоролся