Чтение онлайн

ЖАНРЫ

Освой самостоятельно С++ за 21 день.

Либерти Джесс

Шрифт:

В C++ существует возможность указать, что мы имеем дело не с двумя одноименными классами, как показано в рис. 13.2, а с одним общим базовым классом (рис. 13.3).

Рис. 13.3. Виртуальное наследование

Для этого класс Animal нужно объявить как виртуальный базовый класс для двух производных классов, Horse и Bird. Класс Animal при этом не подвергается никаким

изменениям. В классах Horse и Bird изменения состоят в том, что в их объявлении указывается виртуальность наследования от базового класса Animal. Класс Pegasus изменяется существенно.

Обычно конструктор класса инициализирует только собственные переменные и переменные-члены базового класса. Из этого правила делается исключение, если используется виртуальное наследование. Переменные основного базового класса инициализируются конструкторами не следующих производных от него классов, а тех, которые являются последними в иерархии классов. Поэтому класс Animal инициализируется не конструкторами классов Horse и Bird, а конструктором класса Pegasus. Конструкторы классов Horse и Bird также содержат команды инициализации базового класса Animal, но при создании объекта Pegasus эта инициализация перекрывается конструктором данного класса.

Листинг 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++ все еще не поддерживают множественное наследование; это осложняет отладку программы, тем более что все возможности, реализуемые этим методом, можно получить и без него.

Поделиться с друзьями: