Вы пытаетесь решить, что теперь стали печально известными в ++ сообщество страшного «Алмаз смерть Проблемы» C. Bjarne Stroustroup, создатель C++, дает классическую иллюстрацию этой проблемы.
class Base {
public:
virtual void Method1() = 0;
virtual void Method2() = 0;
};
class Base1 : public Base
{
public:
virtual void Method1();
virtual void Method2();
};
class Base2 : public Base
{
public:
virtual void Method1();
virtual void Method2();
}
class Concrete : public Base1, public Base2
{
virtual void Method1();
virtual void Method2();
}
Посмотрите на вышеуказанную иерархию классов. Как вы правильно догадались, компилятор не знает, какую версию Method1() и Method2() следует принять в определение класса Concrete.Поскольку у Base1 и Base2 есть свои собственные версии Method1() и Method2(), у компилятора есть 2 варианта выбора этих определений, и он просто запутывается и начинает бросать все эти ошибки со словом «двусмысленный», брошенным по всему месту.
Решение, предложенное Bjarne Stroustroup для проблемы, - это уловка под названием «Виртуальное наследование». Фактически, вам нужно ввести ключевое слово virtual, когда вы выходите из класса «Base».
class Base1 : virtual public Base
{
public:
virtual void Method1();
virtual void Method2();
};
class Base2 : virtual public Base
{
public:
virtual void Method1();
virtual void Method2();
}
Это говорит компилятору, что, хотя есть несколько копий базы в Base1 и Base2, они должны по сути точки к одной и той же версии базы. Это гарантирует, что при определении: класс бетона: общественный Base1, общественный Base2 { }
«Бетон» получает только одну копию «базы», которая, как «Base1» и «Base2» указывают на , тем самым устраняя двусмысленность для компилятора. Как это достигается компилятором? Каждый класс с виртуальными методами связан с чем-то, называемым таблицей виртуальных функций или vtable. Vtable имеет указатель на все виртуальные методы этого класса. Когда классы Base1 и Base2 загружаются, vtables для этих 2 классов содержат единственный указатель на класс Base. Аналогично, когда Concrete загружается, vtable для Concrete также указывает на один и тот же единственный экземпляр Base, эффективно гарантируя, что есть один экземпляр Base.
При создании экземпляров Безусловных есть моменты, которые необходимо учитывать. Вам нужно будет явно вызвать конструктор Base, точно так же, как вы явно вызываете конструкторы Base1 и Base2. Что-то вроде
Concrete() : Base(), Base1(), Base2()
{
}
Кроме того, если имеется явный вызов конструктора Base() в конструкторах Base1 и Base2, это будет пропускаться при инстанцировании бетона и конструктор базы будет вызываться непосредственно.
Основной принцип, если вы хотите, чтобы сделать несколько наследований, вам нужно использовать Virtaul explicilty, другой мудрый компилятор запросит ошибку, потому что компилятор не может решить маршрут родительского Множественное наследование также известно как проблема с алмазом –