Архитектура Аудит Военная наука Иностранные языки Медицина Металлургия Метрология Образование Политология Производство Психология Стандартизация Технологии |
Глава22.Знакомствосвиртуальнымифункциями-членами:настоящиел
class Base
virtual void f cout << "Мы в классе Base\n"; } }; class Subclass : public Base
virtual void { cout << "Мы в классе
void b)
(); позднее связывание ) int argcs, char*
Base Subclass sc; cout << "Вызываем функцию
cout << "Вызываем функцию
return 0;
Ключевое слово virtua l сообщает C++ о том, что n () является полиморфной функцией-членом. Это так называемое виртуальное объявление f n (} означает, что ее вызовы будут связаны позже, если есть хоть какие-то сомнения по поводу типа аргу- мента, с которым будет вызываться функция f n () на этапе выполнения. В приведенном фрагменте () вызывается через промежуточную функцию (). Когда функции tes t () передается объект базового класса, вызывает функцию : n (). Но когда функции tes t () передается объект класса Subclass, этот же вызов обращается к функции Subclass : : () . Запуск программы приведет к выводу на экран таких строк: Вызываем функцию Мы в классе Вызываем функцию Мы в классе
Если вы уже освоились с отладчиком вашей среды C++, настоятельно ре- комендую выполнить этот пример в пошаговом режиме.
Достаточно объявить функцию виртуальной только в базовом классе. Вир- туальность наследуется подклассами автоматически. Однако в этой книге я следую стандарту кодирования, в соответствии с которым функции объ- являются виртуальными везде.
Часть IV, Наследование Поскольку вы уже познакомились с кое-какими деталями объявления виртуальных вернемся к примеру с и посмотрим, как они выглядят в про- грамме. Рассмотрим приведенный ниже фрагмент кода. //нужно для функции class !) {}; class Nachos : public Stuff и есть наше блюдо
// Обычная печь class Oven {
virtual void nachos); //необходимые нам поддержки void //включить печь void //выключить печь void s) ; //поместить блюдо внутрь void s) ; //вынуть блюдо
protected: float temp; }; void nachos) { //pa печь (включить и ждать с цикла) блюдо до температуры 3
while (temp<350) {} //поместить блюдо внутрь на минут
;
//вынуть и выключить печь ; turrOff(); }
{
: Oven virtual void nachos); void
void nachos) { — температура не нужна //сначала поместить блюдо внутрь, затем включить
; / минуту // ( полминуты позернуть блюдо) //подождать 30 секунд
sleep(30); //подождать 30 секунд
Глава22.Знакомство свиртуальнымифункциями-членами:настоящиели //сначала выключить затем вынуть блюдо turnOff();
Nachos oven) f //Смешать ингредиенты Nachos n; //теперь приготовить блюдо //в любой печи, которая у вас есть
//Съесть результат... return } Здесь вы видите класс который объявлен как подкласс stuf f (Блюдо). Класс Oven укомплектован функциями turnOn () , turno f f (), inser t () и remove () (с помощью последних двух блюдо помешается в печь и вынимается из нее). Кроме того, класс Oven содержит функцию-член cook ), которая объ- явлена виртуальной. cook была объявлена виртуальной, поскольку в подклассе Microwave, который наследуется от класса Oven, она работает по-другому. Функ- ция Oven: разогревает печь температуры помешает закус- ки внутрь и готовит их 15 минут. Затем оставшиеся от блюда угольки извлекаются из печи. В отличие от представления класса Oven о приготовлении закусок, функ- ция Microwave: : cook помещает блюдо внутрь, включает печь на 30 се- кунд, поворачивает блюдо и ждет еше 30 секунд, прежде чем выключить печь и вы- нуть Все это хотя и превосходно, но всего присказка, сказка — впереди. Функции makeNachos () объект Oven некоторого типа. Получив такую oven (печь), она собирает все ингредиенты в объект п и готовит его, вызывая cook (). Какая именно функция используется для этого Oven : : cook () или Microwave : : cook () , зависит от текущего типа печи. Функция makeNachos (} не имеет об этом представ- ления, да ее это и не интересует. Так чем же так хорош полиморфизм? Во-первых, он возлагает заботу о подробно- стях работы печи на ее а не на того, кто в ней готовит. Такое разделе- ние труда позволяет переложить детали работы печи на плечи программиста, специа- лизирующегося по печам. Во-вторых, полиморфизм может значительно упростить код. Посмотрите на то, как просто, без использования подробностей работы микроволновой печи реализована функция makeNachos!) (я понимаю, что в данном случае эта функция не была бы намного сложнее с деталями, но ведь полиморфизм работает не только с печами!). И наконец, когда появится новый подкласс печей со своей функцией-членом : не нужно будет ничего менять в makeNachos {), чтобы воспользоваться новой печью. Полиморфизм автома- тически вызовет новую функцию при необходимости. Что и говорить, полиморфизм, раскрывающий перед нами всю мощь наследова- ния, отличная вещь!
Часть IV. Наследование не tfufuni/альной Даже если вы считаете, что каждая функция вызывается с использованием позд- него связывания, это отнюдь не означает, что так и есть на самом деле. C++ на этапе компилирования никак не указывает, какое связывание было использовано — ранее или позднее.
Для осуществления вызова с поздним связыванием нужно следить за тем, что- бы все необходимые функции-члены были объявлены идентично, включая воз- вращаемый тип. Если объявлена в подклассе с другими аргумента- ми, она не будет переопределена как полиморфная, независимо от того, объявле- на она виртуальной или нет. Например, измените приведенную выше функцию так, чтобы ее аргументы не совпадали с аргументами функции базового класса, и вновь выполните программу.
class Base {
virtual void x) { cout << "Мы в классе Base, int x " << x <<
c{lass : Base v{irtualvoidfn(floatx) cout « "Мы в классе float x = " « x « "\n";
void b)
int i = fn //Здесь не позднее связывание float f = //И здесь тоже не используется
int argcs, char* { Ease Subclass sc; cout << "Вызываем функцию test; cout << "Вызываем функцию ; return
|
Последнее изменение этой страницы: 2019-04-19; Просмотров: 193; Нарушение авторского права страницы