Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Либерти Джесс. Освой самостоятельно С++ за 21 день. - royallib.ru.rtf
Скачиваний:
1
Добавлен:
01.07.2025
Размер:
2.55 Mб
Скачать

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

В листинге 13.5 решалась проблема неопределенности, а именно: от какого базового класса унаследована функция getAge() в объекте класса Pegasus. Но в действительности этот метод производится от одного общего базового класса Animal.

В 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 Whinny()const { 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 Chirp()const { cout << "Chirp... "; }

51:       virtual void Fly()const

52:          { cout << "I can fly! I can fly! I can fly! "; }

53:       virtual COLOR GetColor()const { 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 Chirp()const { 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 GetColor()const { 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.