Множественное наследование. Рассмотрим две проблемы, которые возникают при множественном наследовании: конфликт имен между суперклассами и повторное наследование

Рассмотрим две проблемы, которые возникают при множественном наследовании: конфликт имен между суперклассами и повторное наследование.

Конфликт имен происходит тогда, когда в двух или более суперклассах случайно оказывается элемент (переменная или операция) с одинаковым именем.

Пример. Определим абстракцию «Работающий студент». Для этого введем более общие абстракции «Работник» и «Студент». Абстракция «Работающий студент» будет наследовать компоненты обеих общих абстракций.

class Worker {

public:

int ID_profession; // код профессии

char* Name; // имя

};

class Student {

public:

int ID_university; // код университета

char* Name; // имя

};

class Student_Worker: public Student, public Worker {... };

Рассмотрим последовательность действий

Student_Worker He;

...

He.ID_profession; // правильно

He.Name; // неправильно – двусмысленно

Конфликт имен элементов подкласса может быть разрешен полной квалификацией имени члена класса, т.е. к именам добавляют префиксы, которые указывают имена тех классов, откуда они пришли.

He.Worker:: Name; // правильно

Повторное наследование возникает тогда, когда в многоуровневой наследственной иерархии какой-либо класс дважды является суперклассом для другого класса.

Продолжим пример с работающим студентом. Анализируя глубже полученную иерархию наследования, мы обнаружим, что и работник, и студент имеют ряд общих признаков, в частности, имя. Разумно ввести еще более общую абстракцию «Человек».

class Person {

public: char* Name; // имя

}

class Worker: public Person {

public: int ID_profession; // код профессии

}

class Student: public Person {

public: int ID_university; // код университета

}

Наследственная иерархия класса Student_Worker представлена на рис. 4.1.

Рис. 4.1 Наследственная иерархия Рис. 4.2 Ромбовидная структура

класса Student_Worker наследования

Для доступа к одной из копий унаследованного эле­мента необходимо воспользоваться явной квалификацией, т.е. добавить к его имени префикс в виде имени класса-источника.

He.ID_profession; // правильно

He.Name; // неправильно – двусмысленно

He.Person:: Name; // неправильно – двусмысленно

He.Worker:: Name; // правильно

He.Student:: Name; // правильно

Продолжая анализ полученной иерархии, заметим, что работающий студент имеет всего одно имя. В результате объект класса Student_Worker должен использовать единственную копию эле­мента Name, унаследованную от Person. В результате приходим к ромбовидной структуре наследования, когда повторяющийся суперкласс в производном классе представлен одним и тем же (совместно используемым) объектом (см. рис 4.2).

В С++ механизмом задания ромбовидной структуры наследования является виртуальное наследование, когда повторяющийся суперкласс объявляется «виртуальным базовым классом». Для задания виртуального наследования используется синтаксис следующего примера.

class Person {...};

class Worker: public virtual Person {...};

class Student: public virtual Person {...};

class Student_Worker: public Student, public Worker {... };

Задача. Укажите ошибочные строки в функции main среди отмеченных буквами А, Б, В, Г, Д, Е.

class Transport // Транспортное средство

{public: String Registration_Number; // регистрационный номер

};

class Land_Transport: public Transport { // Сухопутное транспортное средство

public: int Shaft; // ведущая ось

};

class Water_Transport: public Transport { // Водное транспортное средство

public: int Displacement; // водоизмещение

};

class Amphibia: public Land_Transport, public Water_Transport {}; // Амфибия

void main() {

Amphibia amph;

...

amph.Shaft; // А

amph.Displacement; // Б

amph.Water_Transport:: Displacement; // В

amph.Registration_Number; // Г

amph.Water_Transport:: Registration_Number; // Д

amph.Transport:: Registration_Number; // Е

}


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: