В следующем коде построение класса C начинается с инициализации A, затем B1, а затем B2 и, наконец, класса C. Однако при инициализации B1 и B2 отладчик проигнорировал инициализацию A (1) и A (2) (которые появляются в списке инициализации B1 и B2 в этом порядке), но не игнорировали инициализацию B2 (3) в списке инициализации C.
Почему это?
Заранее спасибо.
Вот код:
struct A {
int i;
A() { i = 0; }
A(int _i) : i(_i) {}
virtual void f() { cout << i; }
};
struct B1 : virtual A {
B1() : A(1) { f(); }
void f() { cout << i+10; }
};
struct B2 : virtual A {
B2(int i) : A(2) { f(); }
};
struct C : B1, B2 {
C() : B2(3) {}
};
int _tmain(int argc, _TCHAR* argv[])
{
C* c = new C();
return 0;
}
Именно так компилятор избегает "алмаза смерти". Если бы были вызваны A (1) и A (2), значит, была дублирующая инициализация базового класса, это цель виртуального наследования - удалить неоднозначные общие базовые элементы.
Для virtual
баз наиболее производный класс должен предоставить аргументы конструктора, например:
struct C
: B1, B2 {
C()
: A(17)
, B2(3) {}
};
Если самый производный класс не упоминает virtual
базу в своем списке инициализаторов, используется конструктор по умолчанию virtual
базы (если их нет, это ошибка).
Причина этого заключается в том, чтобы избежать двусмысленности того, какой из производных классов должен предоставить аргументы конструктора для общей virtual
базы: наиболее производный класс лучше всего знает, что на самом деле необходимо.