/* Класс derived3 наследует оба класса derived1 и derived2. Это означает, что в классе derived3 существует две копии класса base!
*/
class derived3 : public derived1, public derived2 {
public:
int sum;
};
int main()
{
derived3 ob;
ob.derived1::i = 10; // Контекст разрешен, используется член i класса derived1.
ob.j = 20;
ob.k = 30;
// Контекст разрешен и здесь.
ob.sum = ob.derived1::i + ob.j + ob.k;
// Неоднозначность ликвидирована и здесь.
cout << ob.derived1::i << " ";
cout << ob.j << " " << ob.k << " ";
cout << ob.sum;
return 0;
}
Виртуальное наследование базового класса гарантирует, что в любом производном классе будет присутствовать только одна его копия.
Применение оператора "::" позволяет программе "ручным способом" выбрать версию класса base (унаследованную классом derived1). Но после такого решения возникает интересный вопрос: а что, если в действительности нужна только одна копия класса base? Можно ли каким-то образом предотвратить включение двух копий в класс derived3? Ответ, как, наверное, вы догадались, положителен. Это решение достигается с помощью виртуальных базовых классов.
Если два (или больше) класса выведены из общего базового класса, мы можем предотвратить включение нескольких его копий в объекте, выведенном из этих классов, что реализуется путем объявления базового класса при его наследовании виртуальным. Для этого достаточно предварить имя наследуемого базового класса ключевым словом virtual.
Для иллюстрации этого процесса приведем еще одну версию предыдущей программы. На этот раз класс derived3 содержит только одну копию класса base.
// Эта программа использует виртуальные базовые классы.
#include <iostream>
using namespace std;
class base {
public:
int i;
};
// Класс derived1 наследует класс base как виртуальный.
class derived1 : virtual public base { public: int j;};
// Класс derived2 наследует класс base как виртуальный.
class derived2 : virtual public base { public: int k;};
/* Класс derived3 наследует оба класса derived1 и derived2. На этот раз он содержит только одну копию класса base.
*/
class derived3 : public derived1, public derived2 {
public:
int sum;
};
int main()
{
derived3 ob;
ob.i = 10; // Теперь неоднозначности нет.
ob.j = 20;
ob.k = 30;
// Теперь неоднозначности нет.
ob.sum = ob.i + ob.j + ob.k;
// Теперь неоднозначности, нет.
cout << ob.i << " ";
cout << ob.j << " " << ob.k << " ";
cout << ob.sum;
return 0;
}
Как видите, ключевое слово virtual предваряет остальную часть спецификации наследуемого класса. Теперь оба класса derived1 и derived2 наследуют класс base как виртуальный, и поэтому при любом множественном их наследовании в производный класс будет включена только одна его копия. Следовательно, в классе derived3 присутствует лишь одна копия класса base, а инструкция ob.i = 10 теперь совершенно допустима и не содержит никакой неоднозначности.
И еще. Даже если оба класса derived1 и derived2 задают класс base как virtual-класс, он по-прежнему присутствует в объекте любого типа. Например, следующая последовательность инструкций вполне допустима.
// Определяем класс типа derived1.
derived1 myclass;