Проблема
Ваш код что-то забыл, и у вас все еще есть два A
объекта в D
объекте. Вы можете проверить это утверждение, добавив члена * publi c int test
к A
и попробуйте следующий код. Вы получите два разных адреса:
D d;
cout << &d.B::test <<endl; // the non virtual A subobject of B
cout << &d.C::test <<endl; // the virtual A subobject of C
Демо-версия
Решение
Все классы , которые разделяют A
виртуально и которые напрямую наследуются от A
, должны объявить виртуальное наследование . Поэтому вам нужно исправить класс B
:
class B: virtual public A {...} // you forgot the virtual here
Приведенные выше фрагменты кода будут работать, как и ожидалось, и вы даже можете обратиться к d.test
, не получив ошибки двусмысленности. Онлайн-демонстрация
Редактирование: деликатная конструкция A
Правила C ++ требуют, чтобы каждый объект с виртуальным подобъектом A
предоставлял конструктор для A
, В вашем случае D
должен предусматривать конструкцию virual A
.
Поскольку явного конструктора нет, D
будет искать конструкцию по умолчанию A
. И он находит его, поскольку вы предоставляете аргумент по умолчанию для конструктора A
. Это вводит в заблуждение, потому что он говорит вам «конструктор», когда на самом деле это был D
, который использовал его.
Если вы удалите этот аргумент по умолчанию, ваш код больше не будет компилироваться. Затем вам нужно что-то вроде этого, чтобы правильно построить A
:
class A {
public:
int test;
A(string text) { cout << "A is constructed: "<<text << endl; }
};
class D : public B, public C {
public:
D() : A("Mandatory, if there is no default consructor") { cout << "Constructor D" << endl; }
};
Демонстрационная версия
Почему правила построения C ++ такие? Потому что, когда у вас есть виртуальное наследование, нет никакой причины, что конструкция A
с помощью B
отрисовывается поверх конструкции на C
. Ни наоборот. С другой стороны, и B
, и C
определяют, как создать свой субобъект A
. Чтобы решить неоднозначность в выборе правильной конструкции, было принято это правило. И это может быть болезненно, если виртуальный класс не имеет конструктора по умолчанию.