Архитектура Аудит Военная наука Иностранные языки Медицина Металлургия Метрология Образование Политология Производство Психология Стандартизация Технологии |
Глава22.Знакомствосвиртуальнымифункциями-членами:настоящиели
Единственное отличие между этой и предыдущей программой в том, что функция f n () в классе Base объявлена как fn(int) , тогда как в версии класса Subclass она объявлена как (float) . Никакой ошибки это не вызовет, поскольку программа полностью корректна. Однако результаты не показывают никаких признаков поли- морфизма: Вызываем функцию
Поскольку первый вызов передает значение типа 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; Нарушение авторского права страницы