Множественное наследование в C++
При обработке этого программного кода компилятор C++ обнаружит, что вызов richard.speak)) содержит неоднозначную ссылку. Оно и понятно, поскольку нельзя однозначно заключить, скажет ли Ричард "War" (война) или "Peace" (мир).
Если мы решим, что метод speak)) класса Republican_Quaker должен "брать пример" с класса Quaker, то проблему можно решить, определив этот метод одним из двух способов:
void S::speak(){ cout << "Peace"; }
…или:
void S::speak)({Quaker::speak)); }
Первый вариант просто перегружает оба наследованных определения метода, а второй в явном виде вызывает один из них, а именно тот вариант, который реализован в классе Quaker.
Однако совершенно незначительное на первый взгляд изменение в файле определения классов может разительно изменить поведение объекта. Предположим, решено удалить объявления методов speak)) из всех классов, кроме Person, как это показано в листинге 7.3.
Листинг 7.3. Файл nixon.h. Объявление классов, версия 2.
class Person public: Person)) {}; virtual "Person)) {}; virtual void speak)){ cout << "Beer";} }; class Republican: public Person public: Republican)) {}; virtual ~Republican)) {}; class Quaker: public Person public: Quaker)) {}; virtual ~Quaker)) {}; class Republican Quaker: public Republican, public Quaker { public: Republican_Quaker() {}; virtual ~Republican_Quaker() {}; }
При обработке такого файла определения компилятор опять выдаст сообщение о неоднозначности ссылки на метод speak (). Это произойдет по той причине, что компилятор сформирует две копии объявления класса Person – по одной для каждого пути наследования, а это приведет к конфликту имен. Чтобы устранить эту неоднозначность, нужно объявить Person как виртуальный базовый класс и для Republican, и для Quaker. Тогда оба производных класса будут ссылаться на единственный объект суперкласса (листинг 7.4).
Листинг 7.4. Файл nixon.h. Объявление классов, версия 3.
class Person { public: Per son () {}; virtual "Person)) {}; virtual void speak(){ cout << "Beer";} И class Republican: virtual public Person { public: Republican)) {}; virtual ~Republican)) {}; }; class Quaker: virtual public Person { public: Quaker)) {}; virtual ~Quaker)).{}; } class Republican_Quaker: public Republican, public Quaker { public: Republican_Quaker {) { }; virtual "Republican_Quaker() {}; }