2011-09-15 2 views
12

Предположит, есть такая иерархия классов:множественного наследования литья из базового класса к различному производному классу

class A //base class 

class B //interface 

class C : public A, public B 

Тогда C создаются объект:

A *object = new C(); 

Можно ли бросить объект B?

Важно: Я предполагаю, что я не знаю, что объект является C. Я просто знаю, что он реализует интерфейс B

ответ

9

No. Это невозможно (прямое литье от A* до B*).

Поскольку адрес A и B находятся в разных местах в class C. Таким образом, бросок будет всегда небезопасным и, возможно, вы можете приземлиться в неожиданном поведении. Demo.

Литье должно всегда проходить через class C. например

A* pa = new C(); 
B* pb = static_cast<C*>(pa); 
        ^^^^ go through class C 

Demo

+0

Спасибо. Неожиданное поведение - это именно то, что у меня было) – Andrew

+0

Но я не могу понять, почему dynamic_cast прошел нормально – Andrew

+0

@Andrew, 'dynamic_cast ' также действителен и будет работать (если классы полиморфны); потому что 'C' действительно является подклассом' A'. Однако в этом случае 'static_cast ' будет лучшей идеей, как это происходит во время компиляции. – iammilind

2

Да, вы должны сначала static_cast объект C *, то вы можете static_cast его снова B (хотя этот последний бросок не нужен, поскольку это стандартное преобразование). Я не уверен, будет ли static_cast объект непосредственно B работать, попробуйте и посмотрите, получаете ли вы ошибки компилятора. reinterpret_cast Входящий объект в B приведет к сбою во время выполнения, поскольку A и B будут иметь разные адреса, если они оба не пустые.

Редактировать После того как вы изменили вопрос, больше не возможно делать то, что вы хотите. Вам нужно знать правильный путь вверх и вниз по дереву наследования, поскольку приведение в сценарий с множественным наследованием с непустыми классами подразумевает сдвиги в указателе.

+0

См. Мое редактирование (важно) – Andrew

0

До тех пор, пока объект получен из B, вы всегда можете отнести объект к B. И, конечно, вы можете вызывать только методы, определенные в интерфейсе B, поскольку виртуальный указатель может получить доступ только к методу, определенному B в виртуальной таблице.

8

путь от любого типа на любой другой dynamic_cast. Но для этого требуется, чтобы объект был polymorphic. В общем случае это требует V-таблицу, чтобы быть связаны как A и B, так что: , если А и В имеют по меньшей мере одну виртуальную функцию, и RTTI не отключить,

A* pa1 = new C; 
A* pa2 = new A; 

B* pb1 = dynamic_cast<B*>(pa1); 
B* pb2 = dynamic_cast<B*>(pa2); 

приведет к Pb2 к be null и pb1, чтобы указать на часть B объекта, содержащую * pa1 в качестве своей части A. (То, что это C или что-то другое, полученное из этих двух оснований, не имеет значения).

В противном случае, когда все должно быть статическим, вы должны пройти через C

B* pb = static_cast<B*>(static_cast<C*>(pa)); 

Обратите внимание, что static_cast<B*>(pA) не может скомпилировать, будучи А и В друг с другом не связаны.

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