ОБЪЕКТНО-ОРИЕНТИРОВАННОЕ ПРОГРАММИРОВАНИЕ В C++ (4-Е ИЗДАНИЕ) (часть 11) онлайн
Виртуальные базовые классы
Прежде чем расстаться с темой виртуальных элементов программирования, нам
следует коснуться вопроса виртуальных базовых классов, так как они имеют от-
ношение к множественному наследованию.
Рассмотрим ситуацию, представленную на рис. 11.3. Базовым классом явля-
ется parent, есть два порожденных класса — Child1, child2 и есть еще четвертый
класс — Grandchild, порожденный одновременно классами Child1 и Child2.
В такой ситуации проблемы могут возникнуть, если метод класса Grandchild
захочет получить доступ к данным или функциям класса Parent. Что в этом слу-
чае будет происходить, показано в программе NORMBASE.

Рис. 11.3. Виртуальные базовые классы
Листинг 11.7. Программа NORMBASE
// normbase.cpp
// неоднозначная ссылка на базовый класс
class Parent
{
protected:
Листинг 11.7 (продолжение)
int basedata;
};
class Child1 : public Parent
{ };
class Child2 : public Parent
{ };
class Grandchild : public Child1, public Child2
{
public:
int getdata()
{ return basedata; } // ОШИБКА: неоднозначность
};
Ошибка компилятора возникла вследствие того, что метод Getdata() из класса
Grandchild попытался получить доступ к basedata из класса parent. И что же в этом
такого? Все дело в том, что каждый из порожденных классов (Child1 и Child2) на-
следует свою копию базового класса Parent. Эта копия называется подобъектом.
Каждый из двух подобъектов содержит собственную копию данных базового
класса, включая basedata. Затем, когда Grandchild ссылается на basedata, к какой
из двух копий базового класса он получает доступ? Ситуация неоднозначная,
о чем компилятор и сообщает.
Для устранения неоднозначности сделаем Child1 и Child2 наследниками вир-
туального базового класса, как показано в примере VIRTBASE.
Листинг 11.8. Программа VIRTBASE
// virtbase.cpp
// Виртуальные базовые классы
class Parent
{
protected:
int basedata;
};
class Child1 : virtual public Parent // наследует копию
// класса Parent
{ };
class Child2 : virtual public Parent // наследует копию
// класса Parent
{ };
class Grandchild : public Child1, public Child2
{
public:
int getdata()
{ return basedata; } // OK: только одна копия
//класса Parent
};
Использование ключевого слова virtual в этих двух классах приводит к тому,
что они наследуют единый общий подобъект базового класса Parent. Так как
теперь у нас есть только одна копия basedata, неоднозначность при обращении
к базовому классу устраняется.
Необходимость использования виртуального базового класса показывает, что
при множественном наследовании возникает ряд концептуальных проблем,
поэтому такой подход должен использоваться осторожно.
12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
