ВНИМАНИЕ: ОТВЕТ ФУНДАМЕНТАЛЬНО ИЗОБРАЖЕН!
Анализ проблемы:
Вы используете multiple inheritance with a diamond problem.
В частности, ваша структура D
наследует одно и то же основание A
класс три раза: один раз прямо (struct D: C,A
) и дважды косвенно (через наследование C). Поскольку базовые классы не являются виртуальными, есть 3 различных суб-объекты для D. C++ 11 Стандарт разделе 10.1/4-5 называет это решетки:
Как правило, вы должны были бы рассортировать членов каждого A
с явной квалификацией, сообщающей компилятору, какой из подобъектов 3 A
вы ссылаетесь. Это объясняется в C++ 11, раздел 10.1/5. Синтаксис для членов должен быть A::a
, C::a
и B::a
в пределах D
, каждый из которых в конце концов предшествует D::
, если вы находитесь на улице.
К сожалению, имя элемента поиск логика в C++ 11 раздела 10.2/5-6 гарантирует, что прямой A
база ВСЕГДА делает другие косвенные A
основ неоднозначны, несмотря на явную квалификацию (или даже using
заявления).
Окончательное решение:
Поскольку проблема вызвана непосредственным базовым классом, а также тот факт, что не существует способов diambiguate этот от других, только действительно рабочий раствор использовать пустой посредник класс, чтобы заставить другое имя:
struct Ob{ int v; }; // v aded here to allow verification of copy of all members
struct A { Ob a; };
struct B : A { Ob b; };
struct A1 : A {}; // intermediary class just for diambiguation of A in C
struct C : A1, B { Ob c; }; // use A1 instead of A
struct A2 : A { }; // intermediary class just for diambiguation of A in D
struct D : C, A2 { // use A2 instead of A
Ob d;
D() { }
D(const D& _d) : C(_d), A2(_d), d(_d.d) { }
};
int main(int ac, char**av)
{
cout << "Multiple inheritance\n";
D x;
x.A2::a.v = 1; // without A2:: it's ambiguous
x.A1::a.v = 2; // without A1:: it's ambiguous
x.B::a.v = 3;
x.b.v = 4;
x.d.v = 5;
D y = x;
cout << "The moment of truth: if not 1 2 3 4 5, there's a problem!\n";
cout << y.A2::a.v << endl;
cout << y.A1::a.v << endl;
cout << y.B::a.v << endl;
cout << y.b.v << endl;
cout << y.d.v << endl;
}
Этот код компилируется и работать с MSVC2013, лязгом 3.4.1 и GCC 4.9.
Другие (не) решения:
Мой предыдущий ответ был основан только на явной квалификации. Несмотря на многие критические замечания, я действительно скомпилировал и протестировал на MSVC2013! Однако их было странно: в редакторе intelisence подчеркивалась двусмысленность, но компиляция прошла отлично без ошибок. Сначала я подумал, что это ошибка в интеллекте, но теперь понимаете, что это был несобственный компилятор (ошибка?)
Ответ, предлагающий D(const D& other) : C(other), A((const B)other), d(other.d)
, компилирует, но не проходит тест. Зачем ? потому что A((const B)other)
поймет other
как B
. Таким образом, A
непосредственно в D
получит инициализацию со значением A
, косвенно унаследованным от B
(так еще A
). Это очень неприятная ошибка, и мне потребовалось некоторое время, чтобы заметить.
Конечно, вы можете использовать виртуальные базовые классы. Тогда в D будет только один подобъект A
, который решает многие проблемы.Однако я не конструирую то, что вы разрабатываете, и для некоторых конструкций требуется решетка, а не виртуализованный алмаз.
Если вы можете позволить себе копию с двумя шагами (шаг 1: инициализация базы по умолчанию, шаг 2: копирование целевого значения на базе), есть, конечно, подходы, использующие двухуровневые функции-члены, возвращающие ссылку на правильную базу. Но это может быть более сложным и подверженным ошибкам, чем простое решение, представленное выше.
Можете ли вы добавить полное сообщение об ошибке компилятора? – Angew
Ohh Я пропустил понимание, yee компилятор ошибка plz. –
Возможно, это полезно: http://stackoverflow.com/questions/6488772/refer-base-class-members-from-derived-class – Jack