Архитектура Аудит Военная наука Иностранные языки Медицина Металлургия Метрология
Образование Политология Производство Психология Стандартизация Технологии


Глава22.Знакомствосвиртуальнымифункциями-членами:настоящиели




Единственное отличие между этой и предыдущей программой в том, что функция f n () в классе Base объявлена как fn(int) , тогда как в версии класса Subclass она объявлена как (float) . Никакой ошибки это не вызовет, поскольку программа полностью корректна. Однако результаты не показывают никаких признаков поли- морфизма:

Вызываем функцию

Мы в   Base, int х = 2
Мы в классе int х 2
Вызываем функцию  
Мы в классе Base, int x = 1
Мы в классе 3ase, х = 2

Поскольку первый вызов передает значение типа int , не удивительно, что компи- лятор вызывает          как с так и с Несколько неожиданно то, что во вто- ром вызове floa t конвертируется в in t и при втором обращении к функции tes t (} вызывается та же функция Base: : (). Это происходит потому, что объект ь, кото- рый передается функции tes t (), является объектом  класса                                             Без полиморфизма

Btest{ ) обращается к Base: : fn (int) .

Если аргументы не полностью совпадают, позднее связывание не ис- пользуется.

 

 

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

class Base

{

//возвращаем копию текущего объекта Base*

{

все, что нужно для создания копии

 

 

Subclass :

1

public:

//возвращаем копию текущего объекта


 

{

 

)

};

void

{


 

 

все, что нужно для создания копии

 

 

=


//функция продолжается. . .

}

С практической точки зрения все естественно: функция копирования гаакеСоруО

должна возвращать указатель на объект типа Subclass, даже если она переопределяет

.

 





Часть  Наследование


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

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

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

Например, приведенный ниже вызов обращается к Base::fn(] , поскольку так указал программист, независимо от того, объявлена fn () виртуальной или нет.

void test (Bases b)

{

//Этот  вызов  не                                                связывания

}

Кроме того, виртуальная функция не может быть встроенной. Чтобы подставить

функцию на место ее вызова, компилятор должен знать ее на этапе компиляции. Та- ким образом, независимо от способа описания виртуальные функции-члены рассмат- риваются как не встроенные.

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

В отличие от конструктора, деструктор может быть объявлен виртуальным. Более того, если он не объявлен виртуальным, вы рискуете столкнуться с неправильной ли- квидацией объекта, как, например, в следующей ситуации:

class Base f

 

-Base();

 

class Subclass : public Base

 

public:

 

void                    pHeapObject)

{

delete pHeapObject; //Здесь вызывается

//независимо от типа

//указателя pHeapObject

)

Если указатель, передаваемый функции inishWithObject (), на самом деле ука-

зывает  на  объект                    деструктор Subclass все равно вызван не будет: по- скольку он не был объявлен виртуальным, используется раннее связывание. Однако, если объявить деструктор виртуальным, проблема будет решена.

А если вы не хотите объявлять деструктор виртуальным? Тому может быть только одна причина: виртуальные функции несколько увеличивают размер объекта. Когда программист определяет первую виртуальную функцию в классе, C++ прибавляет

 


Поделиться:



Последнее изменение этой страницы: 2019-04-19; Просмотров: 176; Нарушение авторского права страницы


lektsia.com 2007 - 2024 год. Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав! (0.011 с.)
Главная | Случайная страница | Обратная связь