Программирование >>  Инициализация объектов класса, структура 

1 ... 298 299 300 [ 301 ] 302 303 304 ... 395


class AbstractObject {

public:

~AbstractObject();

virtual void doit() = 0; ...

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

NameQuery nq( Sneezy ); Query q( nq );

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

ery *pq = &nq; Почему в инструкции

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

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

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

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

Упражнение 17.12

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

Упражнение 17.13



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

Base* Derived::copy( Derived* );

(c) ostream& Base::print( int, ostream&=cout ); Derived* Derived::copy( Vase* ) ;

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

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

Упражнение 17.16

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

Упражнение 17.17

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

pq->eval();

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

q.eval();

экземпляр из Query? Упражнение 17.15

(a) Base* Base::copy( Base* ); Какие из повторных объявлений виртуальных функций в классе Derived неправильны:



class Object { public:

virtual void doit() = 0;

...

protected:

virtual ~Obj ect();

class MyObject : public Object {

public:

MyObject( string isA ); string isA() const; protected:

string isA;

17.6. Почленная инициализация и присваивание A

При проектировании класса мы должны позаботиться о том, чтобы почленная инициализация (см. раздел 14.6) и почленное присваивание (см. раздел 14.7) были реализованы правильно и эффективно. Рассмотрим связь этих операций с наследованием.

До сих пор мы не занимались явной обработкой почленной инициализации. Посмотрим, что происходит в нашей иерархии классов Query по умолчанию.

class Query {

public: ...

protected:

int paren;

set<short> * solition; vector<location> loc;

...

В абстрактном базовом классе Query определены три нестатических члена: };

Член solution, если он установлен, адресует множество, память для которого выделена в хипе функцией-членом vec2set() . Деструктор Query применяет к solution оператор delete.

Класс Query должен предоставлять как явный копирующий конструктор, так и явный копирующий оператор присваивания. (Если вам это непонятно, перечитайте раздел 14.6.) Но сначала посмотрим, как почленное копирование по умолчанию происходит без них.

Производный класс NameQuery содержит объект-член типа string и подобъект базового Query. Если есть объект folk класса NameQuery:

NameQuery folk( folk ); то инициализация music с помощью folk



1 ... 298 299 300 [ 301 ] 302 303 304 ... 395

© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки.
Яндекс.Метрика