{//...}
Main()
{D d;
d.func();}
Одразу виникає синтаксичне питання: яка функція func() викликається – успадкована класом В чи С? Формально тут присутній розглянутий вище конфлікт імен. Бачимо, що у випадку, коли один клас успадковується іншим кілька разів (через множинне успадкування), можуть виникнути негативні моменти. Такі помилки виявляються на етапі компіляції. У прикладі клас A успадковується у D два рази, будучи базовим для класів В i С. Очевидно, що проблеми можуть виникнути й у тому випадку, коли класи В та С мають конструктори, які iнiцiалiзують поле data. Тоді клас D також повинен мати конструктор, хоча б для того, щоб викликати конструктори базових класів. Однак при цьому виникне неоднозначність при iнiцiалiзацiї поля data.
Визначимо ще один клас:
class E:
Public A,
Public D
{\\...}
У цьому випадку також на етапі компіляції з'явиться помилка:
A is inaccessible becouse also in D
(А недоступний, оскільки він уже в D). Для виходу із таких ситуацій використовуються віртуальні базові класи.
Віртуальні базові класи. Синтаксично для оголошення базового класу віртуальним достатньо в базовому списку вказати ключове слово virtual перед атрибутом доступу:
|
|
class<ім’я похідного класу>:virtual<атрибут доступу><ім’я базового класу>,...
Семантично така конструкція вказує компілятору, що у випадку множинного успадкування береться до уваги лише одна копія базового класу. При цьому ліквідується небезпека повторного успадкування. Ключове слово virtual має бути присутнім у всіх випадках, де можливе повторне успадкування базового класу. Якщо в нашому прикладі оголосити базовий клас А віртуальним, то жодних негативних моментів, пов'язаних із повторним успадкуванням, не буде:
Class A
{protected:
int data;
public:
void func(void){//тіло}};
Class B:virtual public A
{//...};
Class C:virtual public A
{//...};
Class D:public B,public C
{//...};
Class E
:virtual public A,
Public D
{//...};
Main()
{D d;
d.func();}
Бачимо, що в описі класів В i С присутнє слово virtual. При цьому ситуація змінюється таким чином: якщо клас А успадковується в кількох класах, то він не дублюватиметься. Розглянемо приклад:
class Company {
private:
char*name;
public:
company(const char*s){name=strdup(s);}
void Display(void){cout<<name<<'\n'}
};
class CocaCola:virtual public Company {
public:
CocaCola(void):Company("CocaCola") { }
};