Теперь давайте посмотрим, каким образом виртуальные функции могут реализовать полиморфное поведение в нашей иерархии служащих.



Пример 4(можно набрать частично)

В примере показаны заголовочные файлы соответственно для классов CommissionEmployee и BasePlusCommissionEmployee. Заметьте, что  единственным отличием этих файлов от приведенных в Примере 1 является спецификация элемент-функций earnings и print как virtual (строки 30-31 в CommissionEmployee.h и 21-22 в BasePlusCommissionEmployee.h). Так как функции earnings и print в классе CommissionEmployee — виртуальные, функции earnings и print класса BasePlusCommissionEmployee заменяют соответствующие функции CommissionEmployee. Теперь, если мы установим указатель базового класса CommissionEmployee на объект производного класса BasePlusCommissionEmployee и используем этот указатель для вызова любой из функций earnings и print, будет активирована функция объекта BasePlusCommissionEmployee. Реализации элемент-функций классов CommissionEmployee и BasePlusCommissionEmployee изменений не требуют, так что мы используем их версии из Примера 1.

Строки 46-57 снова демонстрируют, что указатель CommissionEmployee, установленный на объект CommissionEmployee, может быть использован для активации функций CommissionEmployee, а указатель BasePlusCommissionEmployee, установленный на объект BasePlusCommissionEmployee, может быть использован для активации функций BasePlusCommissionEmployee. Строка 60 устанавливает указатель базового класса commissionEmployeePtr на объект производного класса basePlusCommissionEmployee. Обратите внимание, что когда строка 67 вызывает функцию print через указатель базового класса, активируется функция print класса BasePlusCommissionEmployee, и строка 67 выводит текст, отличный от выводимого строкой 59 в source.cpp из Примера 1 (когда элемент-функция print не была объявлена виртуальной).

Мы видим, что объявление элемент-функции как virtual заставляет программу динамически определять по типу объекта, а не типу дескриптора, какая из функций должна быть вызвана. Такое решение относительно вызываемой функции является примером полиморфизма. Еще раз заметьте, что когда указатель commissionEmployeePtr ссылается на объект CommissionEmployee (строка 46), вызывается функция print из CommissionEmployee, а когда тот же указатель ссылается на объект BasePlusCommissionEmployee, вызывается функция из BasePlusCommissionEmployee. Таким образом, одно и то же сообщение — в данном случае print, — посылаемое (через указатель базового класса) различным объектам, связанным с этим базовым классом отношениями наследования, принимает различные формы; это — полиморфное поведение.


 

 

Сводка допустимых присваиваний объектов указателям базового и производного классов

1. Установка указателя базового класса на объект базового класса является

естественной — вызовы, производимые через указатель базового класса, просто активируют функции базового класса.

 

commissionEmployeePtr = &commissionEmployee;

 

2. Установка указателя производного класса на объект производного класса является естественной — вызовы, производимые через указатель производного класса, просто активируют функции производного класса.

 

basePlusCommissionEmployeePtr = &basePlusCommissionEmployee;

 

3. Установка указателя базового класса на объект производного класса безопасна, поскольку объект производного класса является также объектом базового класса. Однако этот указатель может использоваться только для активации элемент-функций базового класса. Если программист попытается сослаться через указатель базового класса на элемент, имеющийся только в производном классе, компилятор сообщит об ошибке. Чтобы избежать этой ошибки, программист должен привести указатель базового

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

 

commissionEmployeePtr = &basePlusCommissionEmployee;

 

4. Установка указателя производного класса на объект базового класса генерирует ошибку компиляции. Отношение является имеет место в направлении от производного класса к непосредственным и косвенным базовым классам, но не наоборот. Объект базового класса не содержит элементов, имеющихся только в производном классе и которые можно было бы вызвать через указатель базового класса.

 

basePlusCommissionEmployeePtr = &commissionEmployee;

 

Поля типа и операторы switch

Один из способов определения типа объекта, инкорпорированного в более крупную программу, является использование оператора switch. Он позволяет различать типы объектов и затем активировать соответствующее конкретному объекту действие. Например, в иерархии фигур, где каждая фигура может иметь атрибут (поле) shapeType, оператор switch может проверять shapeType, определяя, какую из функций print следует вызвать.

Однако при этом возникает масса потенциальных проблем. Программист может забыть сделать проверку типа там, где она необходима, или упустить из виду какие-то варианты в switch. При добавлении нового типа программист может забыть вставить новые case-метки во все операторы switch, имеющие отношение к модификации. При любом добавлении или удалении класса необходимо внести изменения во все операторы switch, имеющиеся в модифицируемой системе; этот процесс может отнять много времени и породить новые ошибки.


 


Дата добавления: 2018-08-06; просмотров: 169; Мы поможем в написании вашей работы!

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






Мы поможем в написании ваших работ!