|
Программирование >> Инициализация объектов класса, структура
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
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |