Рассмотрим ситуацию с не виртуальным базовым классом:
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, поэтому у нас просто недостаточно информации для работы приведения вниз.
person
In silico
schedule
17.08.2010