Меню сайта

Урок 38 Полиморфизм в C++


ЧТО ТАКОЕ ПОЛИМОРФИЗМ

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


class phone

{
public:
— — -void dial(char «number) { cout &lt-&lt- «Набор номера » &lt-&lt- —number &lt-&lt- endl- }
— — -void answer(void) { cout &lt-&lt- «Ожидание ответа»&lt-&lt- endl- } —
— — -void hangup(void) { cout &lt-&lt- «Звонок выполнен — повесить трубку» —
&lt-&lt- endl- }
— — -void ring(void) { cout &lt-&lt- «Звонок, звонок, звонок»&lt-&lt- endl-) —
— — -phone(char *number) { strcpy(phone::number, number)- }-
private:
— — -char number[13]-
)-

Следующая программа PHONEONE.CPP использует классphone -для создания объекта-телефона:

#include &lt-iostream.h&gt-

#include &lt-string.h&gt-

class phone

{
public:
— — -void dial(char *number) { cout &lt-&lt- «Набор номера » &lt-&lt- number&lt-&lt- endl- }
— — -void answer(void) { cout &lt-&lt- «Ожидание ответа»&lt-&lt- endl- } —
— — -void hangup(void) { cout &lt-&lt- «Звонок выполнен — повесить трубку» &lt-&lt- endl- } —
— — -void ring(void) { cout &lt-&lt- «Звонок, звонок, звонок» &lt-&lt- endl- } —
— — -phone(char *number) { strcpy(phone::number, number)- }-
private:
— — -char number[13]-
}-

void main(void)

{
— — -phone telephone(«555-1212»)- —
— — -telephone.dial(«212-555-1212»)-
}

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

Поскольку вы знаете наследование, то примете решение породить классы —touch_tonepay_phone -из —класса phone, -как показано ниже:

class touch_tone : phone

{
public:
— — -void dial(char * number) { cout &lt-&lt- «Пик пик Набор номера» —&lt-&lt- number &lt-&lt- endl- }
— — -touch_tone(char *number) : phone(number) { } —
}-

class pay_phone : phone

{
public:
— — -void dial(char * number)

— — -{
— — — — — -cout &lt-&lt- «Пожалуйста, оплатите » —
&lt-&lt- amount &lt-&lt- » центов»&lt-&lt- endl-
— — — — — -cout &lt-&lt- «Набор номера «&lt-&lt- number —&lt-&lt- endl- —
— — -}

— — -pay_phone(char *number, int amount) : phone(number) { —pay_phone::amount = amount- } —
private:
— — -int amount-
}-

Как видите, классыtouch_tonepay__phone -определяют свой собственный методdial. -Если вы предположите, что методdial класса, phone -основан на дисковом телефоне, то вам не потребуется создавать класс для дискового телефона. Следующая программа NEWPHONE.CPP использует эти классы для создания объектовrotary, touch_tonepay_phone:

#include &lt-iostream.h&gt-

#include &lt-string.h&gt-

class phone

{
public:
— — -void dial(char *number) { cout &lt-&lt- «Набор номера «&lt-&lt- —number &lt-&lt- endl- }
— — -void answer(void) { cout &lt-&lt- «Ожидание ответа»&lt-&lt- endl- } —
— — -void hangup(void) { cout &lt-&lt- «Звонок выполнен — повесить трубку» &lt-&lt- endl- } —
— — -void ring(void) { cout &lt-&lt- «Звонок, звонок, звонок» &lt-&lt- endl- } —
— — -phone(char *number) { strcpy(phone::number, number)- }-
protected:
— — -char number[13]-
)-

class touch_tone : phone

{
public:
— — -void dial(char *number) { cout &lt-&lt- «Пик пик Набор номера» &lt-&lt- number &lt-&lt- endl- }
— — -touch_tone(char *number) : phone(number) { } —
}-

class pay_phone : phone

{
public:
— — -void dial(char * number) { cout &lt-&lt- «Пожалуйста, оплатите » &lt-&lt- amount &lt-&lt- » центов»&lt-&lt- endl- —cout &lt-&lt- «Набор номера — — — — — —» &lt-&lt- -number &lt-&lt- endl- } —
— — -pay_phone(char * number, int amount) : phone(number) { —
pay_phone::amount = amount- }
private:
— — -int amount —
}-

void main (void)

{
— — -phone rotary(«303-555-1212»)-
— — -rotary.dial(«602-555-1212»)-
— — -touch_tone telephone(«555-1212»)-
— — -telephone.dial(«212-555-1212»)-
— — -pay_phone city_phone(«555-1111», 25)-
— — -city_phone.dial(«212-555-1212»)-
}

Если вы откомпилируете и запустите эту программу, на экране дисплея появится следующий вывод:


С:&gt- NEWPHONE &lt-Enter&gt-

Набор номера 602-555-1212

Пик пик Набор номера 212-555-1212

Пожалуйста, оплатите 25 центов

Набор номера 212-555-1212

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


СОЗДАНИЕ ПОЛИМОРФНОГО ОБЪЕКТА-ТЕЛЕФОНА

После того как вы показали начальству вашу новую телефонную программу, ваше руководство сказало вам, что ваш объект-телефон должен уметь эмулировать дисковый, кнопочный или платный телефон на выбор. Другими словами, для одного звонка объект-телефон мог бы представлять кнопочный аппарат, для другого выступал бы как платный телефон и т.д. Иначе говоря, от одного звонка к другому ваш объект-телефон должен изменять форму.

В этих разных классах телефона существует единственная отличающаяся функция — это методdial. -Для создания полиморфного объекта вы сначала определяете функции базового класса, которые отличаются от функций производных классов тем, что они —виртуальные,предваряя их прототипы ключевым словомvirtual, -как показано ниже:

class phone

{
public:
— — -virtual void dial(char number) { cout &lt-&lt- «Набор номера » &lt-&lt- number &lt-&lt- endl- }
— — -void answer(void) { cout &lt-&lt- «Ожидание ответа»&lt-&lt- endl- } —
— — -void hangup(void) { cout &lt-&lt- «Звонок выполнен — повесить трубку» &lt-&lt- endl- }
— — -void ring(void) { cout &lt-&lt- «Звонок, звонок, звонок» &lt-&lt- endl- }
— — -phone(char *number) { strcpy(phone::number, number)- }-
protected:
— — -char number[13]-
}-

Далее в программе вы создаете указатель на объект базового класса. Для вашей телефонной программы вы создадите указатель на базовый класс —phone:

phone *poly_phone-

Для изменения формы объекта вы просто присваиваете этому указателю адрес объекта производного класса, как показано ниже:


poly_phone = (phone *) &amp-home_phone-

Символы(phone *), -которые следуют за оператором присваивания, являются оп
ератором приведения типов, который сообщает компилятору C++, что все в порядке, необходимо присвоить адрес переменной одного типа (touch_tone) -указателю на переменную другого типа (phone). -Поскольку ваша программа может присваивать указателю объекта
poly_phoneадреса различных объектов, то этот объект может изменять форму, а следовательно, является полиморфным. Следующая программа POLYMORP.CPP использует этот метод для создания объекта-телефона. После запуска программы объект —poly_phone -меняет форму с дискового телефона на кнопочный, а затем на платный:

#include &lt-iostream.h&gt-

#include &lt-string.h&gt-

class phone

{
public:
— — -virtual void dial(char *number) { cout &lt-&lt- «Набор номера » &lt-&lt- number &lt-&lt- endl- }
— — -void answer(void) { cout &lt-&lt- «Ожидание ответа»&lt-&lt- endl- } —
— — -void hangup(void) { cout &lt-&lt- «Звонок выполнен — повесить трубку» &lt-&lt- endl- } —
— — -void ring(void) { cout &lt-&lt- «Звонок, звонок, звонок» &lt-&lt- endl- } —
— — -phone(char *number) { strcpy(phone::number, number)- }-
protected:
— — -char number[13] —
}-

class touch_tone : phone

{ —
public:
— — -void dial(char * number) { cout &lt-&lt- «Пик пик Набор номера» &lt-&lt- number &lt-&lt- endl- } —
— — -touch_tone(char *number) : phone(number) { }
}-

class pay_phone: phone

{
public:
— — -void dial(char *number) { cout &lt-&lt- «Пожалуйста, оплатите » &lt-&lt- amount &lt-&lt- » центов»&lt-&lt- endl- —cout &lt-&lt- «Набор номера « — — — — — -&lt-&lt- number &lt-&lt- endl- } —
— — -pay_phone(char *number, int amount) : phone(number) { —
pay_phone::amount = amount- } —
private:
— — -int amount-
}-

void main(void)

{
— — -pay_phone city_phone(«702-555-1212», 25)-
— — -touch_tone home_phone(«555-1212»)-
— — -phone rotary(«201-555-1212») —
— — — — — -// Сделать объект дисковым телефоном —
— — -phone *poly_phone = &amp-rotary-
— — -poly_phone-&gt-dial(«818-555-1212»)-
— — — — — -// Заменить форму объекта на кнопочный телефон —
— — -poly_phone = (phone *) &amp-home_phone-
— — -poly_phone-&gt-dial(«303-555-1212»)-
— — — — — -// Заменить форму объекта на платный телефон —
— — -poly_phone = (phone *) &amp-city_phone-
— — -poly_phone-&gt-dial(«212-555-1212»)-
}

Если вы откомпилируете и запустите эту программу, на экране дисплея появится следующий вывод:


С:&gt- POLYMORP &lt-ENTER&gt-

Набор номера 818-555-1212

Пик пик Набор номера
303-555-1212

Пожалуйста, оплатите 25 центов

Набор номера 212-555-1212

Поскольку объектpoly_phone -изменяет форму по мере выполнения программы, он является полиморфным.

Полиморфные объекты могут изменять форму во время выполнения программы

Полиморфный объект представляет собой такой объект, который может изменять форму во время выполнения программы. Для создания полиморфного объекта ваша программа должна использовать указатель на объект базового класса. Далее программа должна присвоить этому указателю адрес объекта производного класса. Каждый раз, когда программа присваивает указателю адрес объекта другого класса, объект этого указателя (который является полиморфным) изменяет форму. Программы строят полиморфные объекты, основываясь на виртуальных функциях базового класса.

ЧТО ТАКОЕ ЧИСТО ВИРТУАЛЬНЫЕ ФУНКЦИИ

Как вы уже знаете, для создания полиморфного объекта ваши программы определяют один или несколько методов базового класса как —виртуальные -функции. Производный класс может определить свою собственную функцию, которая выполняется вместо виртуальной функции базового класса, или использовать базовую функцию (другими словами, производный класс может и не определять свой собственный метод). В зависимости от программы иногда не имеет смысла определять виртуальную функцию в базовом классе. Например, объекты производных типов могут настолько сильно отличаться, что им не нужно будет использовать метод базового класса. В таких случаях вместо определения операторов для виртуальной функции базового класса ваши программы могут создать —чисто виртуальную функцию,которая не содержит операторов.

Для создания чисто виртуальной функции ваша программа указывает прототип функции, но не указывает ее операторы. Вместо них программа присваивает функции значение ноль, как показано ниже:


class phone

{
public:
— — -virtual void dial (char *number) =0- // Чисто виртуальная -функция —
— — -void answer(void) { cout &lt-&lt- «Ожидание ответа»
&lt-&lt- endl- }
— — -void hangup(void) { cout &lt-&lt- «Звонок выполнен — повесить трубку» &lt-&lt- endl- } —
— — -void ring(void) { cout &lt-&lt- «Звонок, звонок, звонок» &lt-&lt- endl- } —
— — -phone(char *number) { strcpy(phone::number, number)- }-
protected:
— — -char number[13]-
}-

Каждый производный класс, определенный в вашей программе, должен определить свою функцию вместо чисто виртуальной функции базового класса. Если производный класс опустит определение функции для чисто виртуальной функции, компилятор C++ сообщит о синтаксических ошибках.

ЧТО ВАМ НЕОБХОДИМО ЗНАТЬ

Полиморфизм представляет собой способность объекта изменять форму во время выполнения программы. В этом уроке рассмотрены шаги, которые вам необходимо выполнить для создания полиморфных объектов. Из урока 39 вы узнаете, как использовать исключител
ьные ситуации в C++ для обеспечения надежности вашей программы. Прежде чем приступить к уроку 39 убедитесь, что вы освоили следующие основные концепции:

    1. Полиморфный объект может изменять форму во время выполнения программы.
    2. Вы создаете полиморфные объекты, используя классы, порожденные от существующего базового класса.
    3. В базовом для полиморфного объекта классе вы должны определить одну или несколько функций как виртуальные(virtual).
    4. В общем случае полиморфные объекты отличаются использованием виртуальных функций базового класса.
    5. Для создания полиморфного объекта вам необходимо создать указатель на объект базового класса.
    6. Для изменения формы полиморфного объекта вы просто направляете указатель на различные объекты, присваивая новый адрес объекта указателю на полиморфный объект.
    7. Чисто виртуальная функция — это виртуальная функция базового класса, для которой в базовом классе не определены операторы. Вместо них базовый класс присваивает такой функции значение 0.
    8. Производные классы должны обеспечить определение функции для каждой чисто виртуальной функции базового класса.

Категория: Обучение C++ | Дата: 27.03.13

Меню раздела
Блок