Освой самостоятельно С++ за 21 день.
Шрифт:
59:
60: Bird::Bird(COLOR color, bool migrates, int age):
61: Animal(age),
62: itsColor(color), itsMigration(migrates)
63: {
64: cout << "Bird constructor...\n";
65: }
66:
67: class Pegasus : public Horse, public Bird
68: {
69: public:
70: void Chirpconst { Whinny; }
71: Pegasus(COLOR, HANDS, bool, long, int);
72: virtual ~Pegasus { cout << "Pegasus destructor...\n";}
73: virtual long GetNumberBelievers const
74: { return itsNumberBelievers; }
75: virtual COLOR GetColorconst { return Horse::itsColor; }
76: virtual int GetAge const { return Horse::GetAge; }
77: private:
78: long itsNumberBelievers;
79: };
80:
81: Pegasus::Pegasus(
82: COLOR aColor,
83: HANDS height,
84: bool migrates,
85: long NumBelieve,
86: int age):
87: Horse(aColor, height,age),
88: Bird(aColor, migrates,age),
89: itsNumberBelievers(NumBelieve)
90: {
91: cout << "Pegasus constructor...\n";
92: }
93:
94: int main
95: {
96: Pegasus *pPeg = new Pegasus(Red. 5, true, 10, 2);
97: int age = pPeg->GetAge;
98: cout << "This pegasus is " << age << " years old.\n";
99: delete pPeg;
100: return 0;
101: }
Результат:
Animal constructor...
Horse constructor...
Animal constructor...
Bird constructor...
Pegasus constructor...
This pegasus is 2 years old.
Pegasus destructor.,.
Bird destructor...
Animal destructor...
Horse destructor...
Animal destructor...
Анализ:
В строке 25 класс Horse производится от класса Animal. Конструктор класса Horse теперь имеет третий параметр age, который передается в базовый класс Animal. Обратите внимание, что в классе Horse метод GetAge не замещается, а просто наследуется.
В строке 46 класс Bird производится от класса Animal. Конструктор этого класса также содержит параметр age, с помощью которого инициализируется базовый класс Animal. Метод GetAge также наследуется этим классом без замещения.
Класс Pegasus производится от двух базовых классов Horse и Bird, поэтому с исходным базовым классом Animal он связан двумя линиями наследования. Если для объекта класса Animal будет вызван метод GetAge, то для преодоления неопределенности нужно точно указать, к какому базовому классу следует обращаться за этим методом, либо метод GetAge следует заместить в классе Pegasus.
В нашем примере программы метод GetAge замещается для класса Pegasus таким образом, что в нем явно указывается обращение к аналогичному методу конкретного базового класса.
Замещение функции с добавлением обращения к методу базового класса позволяет решить две проблемы. Во-первых, преодолевается неопределенность обращения к базовым классам; во-вторых, функцию можно заместить таким образом, что в производном классе при обращении к этой функции будут выполняться дополнительные операции, которых не было в базовом классе. Причем по желанию программиста эти дополнительные операции могут выполняться до вызова функции базового класса или после вызова с использованием значения, возвращенного функцией базового класса.
Конструктор класса Pegasus принимает пять параметров: цвет крылатого коня, его рост (в футах); логическую переменную, которая определяет, мигрирует сейчас это животное или мирно пасется на пастбище; число людей, верящих в существование Пегаса,
и возраст животного. В строке 87 конструктор инициализирует переменные, определенные в классе Horse (цвет, рост и возраст). В следующей строке инициализируется часть, относящаяся к классу Bird: цвет, миграции и возраст. Наконец, в строке 89 инициализируется переменная itsNumberBelievers, относящаяся непосредственно к классу Pegasus.
Вызов конструктора класса Horse в строке 87 выполняет операторы, записанные в строке 38. С помощью параметра age конструктор класса Horse инициализирует переменную itsAge, унаследованную классом Horse от класса Animal. Затем инициализируются две переменные-члена класса Horse — itsColor и itsHeight.
Вызов конструктора класса Bird в строке 88 выполняет операторы, записанные в строке 60. И в данном случае параметр age используется для инициализации переменной-члена, унаследованной классом Bird от класса Animal.
Обратите внимание, что значение параметра цвета объекта Pegasus используется для инициализации соответствующих переменных-членов обоих классов, Bird и Horse. Параметр age также инициализирует переменную itsAge обоих этих классов, унаследованную ими от базового класса Animal.
Виртуальное наследование
В листинге 13.5 решалась проблема неопределенности, а именно: от какого базового класса унаследована функция getAge в объекте класса Pegasus. Но в действительности этот метод производится от одного общего базового класса Animal.
В C++ существует возможность указать, что мы имеем дело не с двумя одноименными классами, как показано в рис. 13.2, а с одним общим базовым классом (рис. 13.3).
Рис. 13.3. Виртуальное наследование
Для этого класс Animal нужно объявить как виртуальный базовый класс для двух производных классов, Horse и Bird. Класс Animal при этом не подвергается никаким изменениям. В классах Horse и Bird изменения состоят в том, что в их объявлении указывается виртуальность наследования от базового класса Animal. Класс Pegasus изменяется существенно.