Освой самостоятельно С++ за 21 день.
Шрифт:
Обычно конструктор класса инициализирует только собственные переменные и переменные-члены базового класса. Из этого правила делается исключение, если используется виртуальное наследование. Переменные основного базового класса инициализируются конструкторами не следующих производных от него классов, а тех, которые являются последними в иерархии классов. Поэтому класс Animal инициализируется не конструкторами классов Horse и Bird, а конструктором класса Pegasus. Конструкторы классов Horse и Bird также содержат команды инициализации базового класса Animal,
Листинг 13.6 представляет собой программный код из листинга 13.5, переписанный таким образом, чтобы можно было воспользоваться преимуществами виртуального наследования.
Листинг. 13.6. Пример использования виртуального наследования
1: // Листинг 13.6.
2: // Виртуальное наследование
3: #include <iostream.h>
4:
5: typedef int HANDS;
6: enum COLOR { Red, Green, Blue, Yellow, White, Black, Brown } ;
7:
8: class Animal // общий базовый класс для двух производных классов horse и bird
9: {
10: public:
11: Animal(int);
12: virtual ~Animal { cout << "Animal destructor...\n"; }
13: virtual int GetAge const { return itsAge; }
14: virtual void SetAge(int age) { itsAge = age; )
15: private:
16: int itsAge;
17: };
18:
19: Animal::Animal(int age):
20: itsAge(age)
21: {
22: cout << "Animal constructor...\n";
23: }
24:
25: class Horse : virtual public Animal
26: {
27: public:
28: Horse(C0L0R color, HANDS height, int age);
29: virtual ^Horse { cout << "Horse destructor...\n"; }
30: virtual void Whinnyconst { cout << "Whinny!... "; }
31: virtual HANDS GetHeight const { return itsHeight; }
32: virtual COLOR GetColor const { return itsColor; }
33: protected:
34: HANDS itsHeight;
35: COLOR itsColor;
36: };
37:
38: Horse::Horse(C0L0R color, HANDS height, intage):
39: Animal(age),
40: itsColor(color),itsHeight(height)
41: {
42: cout << "Horse constructor...\n";
43: }
44:
45: class Bird : virtual public Animal
46: {
47: public:
48: Bird(COLOR color, bool migrates, int age);
49: virtual ~Bird { cout << "Bird destructor...\n"; }
50: virtual void Chirpconst { cout << "Chirp... "; }
51: virtual void Flyconst
52: { cout << "I can fly! I can fly! I can fly! "; }
53: virtual COLOR GetColorconst { return itsColor; }
54: virtual bool GetMigration const { return itsMigration; }
55: protected:
56: COLOR itsColor;
57: bool itsMigration;
58: };
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: private:
77: long itsNumberBelievers;
78: };
79:
80: Pegasus::Pegasus(
81: COLOR aColor,
82: HANDS heigbt,
83: bool migrates,
84: long NumBelieve,
85: int age):
86: Horse(aColor, height,age),
87: Bird(aColor, migrates,age),
88: Animal(age*2),
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...
Bird constructor. . .
Pegasus constructor...
Tnis pegasus is 4 years old.
Pegasus destructor...
Bird destructor...
Horse destructor...
Animal destructor...
Анализ: В строке 25 класс Horse виртуально наследуется от класса Animal, а в строке 45 так же наследуется класс Bird. Обратите внимание, что конструкторы обоих классов по-прежнему инициализируют класс Animal. Но как только создается объект Pegasus, конструктор этого класса заново инициализирует класс Animal, отменяя прежние инициализации. Убедиться в этом вы можете по результату, выводимому программой на экран. При первой инициализации переменной itsAge присваивается значение 2, но конструктор класса Pegasus удваивает это значение. В результате строка 98 программы выводит на экран значение 4.
Проблемы с неопределенностью наследования метода в классе Pegasus больше не возникает, поскольку теперь метод GetAge наследуется непосредственно из класса Animal. В то же время при обращении к методу GetColor по-прежнему необходимо явно указывать базовый класс, так как этот метод объявлен в обоих классах, Horse и Bird.
Проблемы с множественным наследованием
Хотя множественное наследование дает ряд преимуществ по сравнение с одиночным, многие программисты с неохотой используют его. Основная проблема состоит в том, что многие компиляторы C++ все еще не поддерживают множественное наследование; это осложняет отладку программы, тем более что все возможности, реализуемые этим методом, можно получить и без него.