Рассмотрит ситуацию с участием невиртуального базового класса:
class A { int a; }
class B : public A { int b; }
class C : public A { int c; }
class D : public B, public C { int d; }
Вот возможный макет памяти:
+-------------+
| A: int a; |
+-------------+
| B: int b; |
+-------------+
| A: int a; |
+-------------+
| C: int c; |
+-------------+
| D: int d; |
+-------------+
D
концов с двумя объектами A
, потому что он наследует от B
и C
, и оба они имеют подобъект A
.
Указатели на переменные-члены обычно реализуются как целочисленное смещение от начала объекта. В этом случае целочисленное смещение для int a
в объекте A
равно нулю. Таким образом, «указатель на int a
типа A
» может быть просто целым смещением нуля.
Чтобы преобразовать «указатель на int a
типа A
» в «указатель на int a
типа B
,» вам просто нужно целое смещение в A
подобъекте, расположенной в B
(первый A
подобъектов).
Чтобы преобразовать «указатель на int a
типа A
» в «указатель на int a
типа C
,» вам просто нужно целое смещение в A
подобъекте, расположенной в C
(второй A
подобъектов).
Поскольку компилятор знает, где B
и C
является относительно A
, компилятор имеет достаточно информации о том, как с A
обратное приведение к B
или C
.
Теперь рассмотрит ситуацию, связанную с виртуальным базовым классом:
struct A { int a; }
struct B : virtual public A { int b; }
struct C : virtual public A { int c; }
struct D : public B, public C { int d; }
Возможная компоновка памяти:
+-------------+
| B: ptr to A | ---+
| int b; | |
+-------------+ |
| C: ptr to A | ---+
| int c; | |
+-------------+ |
| D: int d; | |
+-------------+ |
| A: int a; | <--+
+-------------+
Виртуальные базовые классы, как правило, осуществляются при наличии B
и C
(который фактически выводит из A
) содержат указатель на один подзаголовок A
. Указатели на подобъект A
необходимы, поскольку местоположение A
относительно B
и C
не является постоянным.
Если все, что мы имели, было «указатель на int a
типа A
,» мы не сможем бросить его в «указатель на int a
типа B
», так как расположение B
и C
подобъектов может варьироваться относительно A
. A
не имеет обратных указателей до B
или C
, поэтому мы просто не располагаем достаточной информацией для работы в режиме downcast.
+1 для образцов ASCII – Bill