17.5.8. Виртуальные функции, конструкторы и деструкторы

17.5.8. Виртуальные функции, конструкторы и деструкторы

Как мы видели в разделе 17.4, для объекта производного класса сначала вызывается конструктор базового, а затем производного класса. Например, при таком определении объекта NameQuery

NameQuery poet( "Orlen" );

сначала будет вызван конструктор Query, а потом NameQuery.

При выполнении конструктора базового класса Query часть объекта, соответствующая классу NameQuery, остается неинициализированной. По существу, poet - это еще не объект NameQuery, сконструирован лишь его подобъект.

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

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

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

Упражнение 17.12

Внутри объекта NameQuery естественное внутреннее представление вектора позиций - это указатель, который инициализируется указателем, хранящимся в отображении слов. Оно же является и наиболее эффективным, так как нам нужно скопировать лишь один адрес, а не каждую пару координат. Классы AndQuery, OrQuery и NotQuery должны конструировать собственные векторы позиций на основе вычисления своих операндов. Когда время жизни объекта любого из этих классов завершается, ассоциированный с ним вектор позиций необходимо удалить. Когда же заканчивается время жизни объекта NameQuery, вектор позиций удалять не следует. Как сделать так, чтобы вектор позиций был представлен указателем в базовом классе Query и при этом его экземпляры для объектов AndQuery, OrQuery и NotQuery удалялись, а для объектов NameQuery - нет? (Заметим, что нам не разрешается добавить в класс Query признак, показывающий, нужно ли применять оператор delete к вектору позиций!)

Упражнение 17.13

Что неправильно в приведенном определении класса:

class AbstractObject {

public:

~AbstractObject();

virtual void doit() = 0;

// ...

};

Упражнение 17.14

Даны такие определения:

NameQuery nq( "Sneezy" );

Query q( nq );

Query *pq =

Почему в инструкции

pq-eval();

вызывается экземпляр eval() из класса NameQuery, а в инструкции

q.eval();

экземпляр из Query?

Упражнение 17.15

Какие из повторных объявлений виртуальных функций в классе Derived неправильны:

(a) Base* Base::copy( Base* );

Base* Derived::copy( Derived* );

(b) Base* Base::copy( Base* );

Derived* Derived::copy( Vase* );

(c) ostream& Base::print( int, ostream&=cout );

ostream& Derived::print( int, ostream& );

(d) void Base::eval() const;

void Derived::eval();

Упражнение 17.16

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

Упражнение 17.17

Найдите ошибку в следующей иерархии классов:

class Object {

public:

virtual void doit() = 0;

// ...

protected:

virtual ~Object();

};

class MyObject : public Object {

public:

MyObject( string isA );

string isA() const;

protected:

string _isA;

};

Поделитесь на страничке

Следующая глава >

Похожие главы из других книг

1.18 Виртуальные Функции

Из книги C++ автора Хилл Мюррей

1.18 Виртуальные Функции Предположим, что мы пишем программу для изображения фигур на экране. Общие атрибуты фигуры представлены классом shape, а специальные атрибуты – специальными классами:class shape (* point center; color col; //... public: void move(point to) (* center=to; draw(); *) point where() (* return center; *) virtual void


5.5 Конструкторы и Деструкторы

Из книги Информатика и информационные технологии: конспект лекций автора Цветкова А В

5.5 Конструкторы и Деструкторы Если у класса есть конструктор, то он вызывается всегда, когда создается объект класса. Если у класса есть деструктор, то он вызывается всегда, когда объект класса уничтожается. Объекты могут создаваться как:1. Автоматический объект:


7.2.6 Конструкторы и Деструкторы

Из книги Информатика и информационные технологии автора Цветкова А В

7.2.6 Конструкторы и Деструкторы Для некоторых производных классов нужны конструкторы. Если у базового класса есть конструктор, он должен вызыватся, и если для этого конструктора нужны параметры, их надо предоставить. Например:class base (* // ... public: base(char* n, short t); ~base(); *);class derived :


7.2.8 Виртуальные Функции

Из книги Справочное руководство по C++ автора Страустрап Бьярн

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


8.5.4 Виртуальные Функции

Из книги Microsoft Visual C++ и MFC. Программирование для Windows 95 и Windows NT автора Фролов Александр Вячеславович

8.5.4 Виртуальные Функции Если базовый класс base содержит virtual (виртуальную) (#8.1) функцию vf, а производный класс derived также содержит функцию vf, то обе функции должны иметь один и тот же тип, и вызов vf для объекта класса derived вызывает derived::vf. Например:struct base (* virtual void vf (); void f (); *);class


2. Конструкторы и деструкторы

Из книги Эффективное использование C++. 55 верных способов улучшить структуру и код ваших программ автора Мейерс Скотт

2. Конструкторы и деструкторы Конструкторы и деструкторы являются специализированными формами методов. Используемые в связи с расширенным синтаксисом стандартных процедур New и Dispose конструкторы и деструкторы обладают способностью размещения и удаления динамических


30. Конструкторы и деструкторы

Из книги Стандарты программирования на С++. 101 правило и рекомендация автора Александреску Андрей

30. Конструкторы и деструкторы Конструкторы и деструкторы являются специализированными формами методов. Используемые в связи с расширенным синтаксисом стандартных процедур New и Dispose конструкторы и деструкторы обладают способностью размещения и удаления динамических


R.10.2 Виртуальные функции

Из книги C++ для начинающих автора Липпман Стенли

R.10.2 Виртуальные функции Если класс base содержит виртуальную (§R.7.1.2) функцию vf, а производный от него класс derived также содержит функцию vf того же типа, тогда вызов vf для объекта класса derived является обращением к derived::vf, даже если доступ к этой функции происходит через


R.15.3 Конструкторы и деструкторы

Из книги автора

R.15.3 Конструкторы и деструкторы Когда управление передается из точки запуска особой ситуации обработчику, то вызываются деструкторы для всех автоматических объектов, построенных с момента входа в проверяемый-блок.Если объект не был построен полностью, то деструкторы


Конструкторы и деструкторы класса

Из книги автора

Конструкторы и деструкторы класса Обычно при создании объекта класса необходимо провести начальную инициализацию объекта, например выделить участок памяти для размещения каких-либо данных, связанных с этим объектом. После окончания использования объекта выделенную


Глава 2 Конструкторы, деструкторы и операторы присваивания

Из книги автора

Глава 2 Конструкторы, деструкторы и операторы присваивания Почти во всех ваших классах будут определены один или несколько конструкторов, деструктор и оператор присваивания. Это функции, которые отвечают за операции создания и инициализации объекта, его уничтожения, а


Конструкторы, деструкторы и копирование

Из книги автора

Конструкторы, деструкторы и копирование Если стандарт привел вас к обрыву, это еще не значит, что вы должны прыгнуть с него. — Норман Даймонд (Norman Diamond) О Большой Четверке специальных функций было сказано достаточно, чтобы вы не удивлялись тому, что им посвящен отдельный


51. Деструкторы, функции освобождения ресурсов и обмена не ошибаются

Из книги автора

51. Деструкторы, функции освобождения ресурсов и обмена не ошибаются РезюмеВсе запуски этих функций должны быть успешными. Никогда не позволяйте ошибке выйти за пределы деструктора, функции освобождения ресурса (например, оператора delete) или функции обмена. В частности,


17.5.4. Виртуальные функции и аргументы по умолчанию

Из книги автора

17.5.4. Виртуальные функции и аргументы по умолчанию Рассмотрим следующую простую иерархию классов:#include iostreamclass base {public:virtual int foo( int ival = 1024 ) {cout " base::foo() -- ival: " ival endl;return ival;}// ...};class derived : public base {public:virtual int foo( int ival = 2048 ) {cout " derived::foo() -- ival: " ival endl;return ival;}// ...};Проектировщик


17.5.5. Виртуальные деструкторы

Из книги автора

17.5.5. Виртуальные деструкторы В данной функции мы применяем оператор delete:void doit_and_bedone( vector Query* *pvec ){// ...for ( ; it != end_it; ++it ){Query *pq = *it;// ...delete pq;}}Чтобы функция выполнялась правильно, применение delete должно вызывать деструктор того класса, на который указывает pq. Следовательно,