Программирование >>  Дополнительные возможности наследования 

1 ... 97 98 99 [ 100 ] 101 102 103 ... 265


17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40

int itsAge; int itsWeight; } ;

class Dog : public Mammal {

public: void MoveOconst;

void Dog;:Move() const {

cout In dog move...\ n Mammal::Move(3);

int mainO {

Mammal bigAnimal; Dog fido;

bigAnimal.Move(2);

fido.Mammal::Move(6); return 0; }

fl Mammal move 2 steps.

Mammal move 6 steps.

В строке 35 создается объект bigAnimal класса Mammal, а в строке 36 - объ- * ект fido класса Dog. В строке 37 вызывается метод Move(int) из базового класса для объекта класса Dog.

В предьщущей версии программы мы столкнулись с проблемой из-за того, что в классе Dog доступен только один замещенный метод Move(), в котором не задаются параметры. Проблема была разрешена явным обращением к методу Move(int) базового класса в строке 38.

Рекомендуется

Повышайте функциональные возможности класса путем создания новых производных классов.

Изменяйте выполнение отдельных функций в производных классах с помощью замещения методов.

Не рекоменддется

Не допускайте сокрытие функций базового класса из-за несоответствия ситатур.



Виртуальные метоуы

в этой главе неоднократно подчеркивалось, что объекты класса Dog одновременно являются объектами класса Mammal. До сих пор под этим подразумевалось, что объекты класса Dog наследуют все атрибуты (данные) и возможности (методы) базового класса. Но в языке С++ принципы иерархического построения классов несут в себе еще более глубинный смысл.

Полиморфизм в С++ развит настолько, что допускается присвоение указателям на базовый класс адресов объектов производных классов, как в следующем примере:

Mammal* pMammal = new Dog;

Данное выражение создает в области динамической памяти новый объект класса Dog и возвращает указатель на этот объект, который является указателем класса Mammal. Это вполне логично, так как собака - представитель млекопитающих.

примечание

в этом суть полиморфизма. Например, можно объявить множество окон разных типов, включая диалоговые, прокручиваемые окна и поля списков, после чего создавать их в программе с помощью единственного виртуального метода draw(). Создав указатель на базовое окно и присваивая этому указателю адреса объектов производных классов, можно обращаться к методу drawO независимо от того, с каким из объектов в данный момент связан указатель. Причем всегда будет вызываться вариант метода, специфичный для класса выбранного объекта.

Затем этот указатель можно использовать для вызова любого метода класса Mammal. Причем если метод был замещен, скажем, в классе Dog, то при обращении к методу через указатель будет вызываться именно вариант, указанный в данном производном классе. В этом суть использования виртуальных функций. Листинг 11.8 показывает, как работает виртуальная функция и что происходит с невиртуальной функцией.

Листинг 11.8. Испшьзвванце ввртвшныхмвторв

2 3 4 5 6 7 8 9

10 11 12 13 14 15 16

Листинг 11.8, Использование виртуальных методов

ftinclude <iostream.h>

class Mammal {

public:

Mammal():itsAge(1) { cout Mammal constructor..,\ n ; } virtual MammalO { cout Mammal destructor. .. \ n ; } void MoveO const { cout Mammal move one step\ n ; } virtual void Speak() const { cout << Mammal speak!\ n ; } protected: int itsAge;



17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35

class Dog : public Mammal {

public:

DogO { cout Dog Constructor. .. \ n ; } virtual DogO { cout Dog destructor, \ n ; } void WagTailO { cout << Wagging Tail,.,\ n ; } void SpeakOconst { cout Woof!\ n ; } void MoveOconst { cout Dog moves 5 steps...\ n ; } } ;

int main() {

Mammal *pDog = new Dog; pDog->Move(); pDog->Speak();

return 0; }

Mammal constructor... Dog Constructor... Mammal move one step

Woof!

В строке 11 объявляется виртуальный метод SpeakO класса Mammal. Предполагается, что данный класс должен быть базовым для других классов. Вероятно также, что данная функция может быть замещена в производных классах.

В строке 30 создается указатель класса Mammal (pDog), но ему присваивается адрес нового объекта производного класса Dog. Поскольку собака является млекопитающим, это вполне логично. Данный указатель затем используется для вызова функции Move(). Поскольку pDog известен компилятору как указатель класса Mammal, результат получается таким же, как при обычном вызове метода MoveO из объекта класса Mammal.

В строке 32 через указатель pDog делается обращение к методу Speak(). В данном случае метод Speak() объявлен как виртуальный, поэтому вызывается вариант функции SpeakO, замещенный в классе Dog.

Это кажется каким-то волщебством. Хотя компилятор знает, что указатель pDog принадлежит классу Mammal, тем не менее происходит вызов версии функции, объявленной в другом производном классе. Если создать массив указателей базового класса, каждый из которых указывал бы на объект своего производного класса, то, обращаясь попеременно к указателям данного массива, можно управлять выполнением всех вариантов замещенного метода. Эта идея реализована в листинге 11.9.

Листинг 11.9. Првизвпиьипе вДращЕННЕ к наАврв виртраньных фвнкцнВ

Листинг 11.9. Произвольное обращение к набору виртуальных функций #include <iostream.h>



1 ... 97 98 99 [ 100 ] 101 102 103 ... 265

© 2006 - 2025 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки.
Яндекс.Метрика