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

1 ... 290 291 292 [ 293 ] 294 295 296 ... 395


class Object { public:

virtual ~Obj ect();

virtual string isA(); protected:

string isA; private:

Object( string s ) : isA( s ) {}

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

Упражнение 17.10

Дано определение базового класса:

мы не предоставляем явного деструктора NameQuery, потому что никаких специальных действий по очистке его объекта предпринимать не нужно. Деструкторы базового класса и класса string для члена name вызываются автоматически;

в деструкторах производных классов оператор delete применяется к указателю типа Query*. Чтобы вызвать не деструктор Query, а деструктор класса того объекта, который фактически адресуется этим указателем, мы должны объявить деструктор базового Query виртуальным. (Более подробно о виртуальных функциях вообще и о виртуальных деструкторах в частности мы поговорим в следующем разделе.)

В нашей реализации неявно подразумевалось, что память для операндов, указатели на которые имеются в объектах классов NotQuery, OrQuery и AndQuery, выделена из хипа. Именно поэтому в деструкторах mi применяли к этим указателям оператор delete. Но язык не позволяет обеспечить истинность такого предположения, так как в нем нет различий между адресами в хипе и вне его. С этой точки зрения наша реализация не застрахована от ошибок.

В разделе 17.7 мы инкапсулируем выделение памяти и конструирование объектов иерархии Query в управляющий класс UserQuery. Это гарантирует выполнение нашего предположения. На уровне программа: в целом следует перегрузить операторы new и delete для классов иерархии. Например, можно поступить следующим образом. Оператор new устанавливает в объекте флажок, говорящий, что память для него выделена из хипа. Перегруженный оператор delete проверяет этот флажок: если он есть, то память освобождается с помощью стандартного оператора delete.

Упражнение 17.7

Идентифицируйте конструкторы и деструкторы базового и производных классов для той иерархии, которую вы выбрали в упражнении 17.2 (раздел 17.1).

Упражнение 17.8

Измените реализацию класса OrQuery так, чтобы он был производным от BinaryQuery. Упражнение 17.9



class ConcreteBase { public:

explicit ConcreteBase( int ); virtual ostream& print( ostream& ); virtual ~Base() ;

static int object count(); protected:

int id;

static int object count;

(a) class C1 : public ConcreteBase { public:

C1( int val )

: id( object count++ ) {}

...

Что неправильно в следующих фрагментах:

(b) class C2 : public C1 {

public:

C2( int val )

: ConcreteBase( val ), C1( val ) {} ...

(c) class C3 : public C2 { public:

C3( int val )

: C2( val ), object count( val ) {} ...

(d) class C4 : public ConcreteBase { public:

C4( int val )

: ConcreteBase ( id+val ){}

...

Упражнение 17.11

В первоначальном определении языка C++ порядок следования инициализаторов в списке инициализации членов определял порядок вызова конструкторов. Принцип,



void Query::display( Query *pb ) {

set<short> *ps = pb->solutions();

...

display();

(или указателя, или ссылки на объект), для которого она вызвана:

Статический тип pb - это Query*. При обращении к невиртуальному члену solutions() вызывается функция-член класса Query. Невиртуальная функция display() вызывается через неявный указатель this. Статическим типом указателя this также является Query*, поэтому вызвана будет функция-член класса Query.

class Query { public:

virtual ostreams print( ostream* = cout ) const;

...

Чтобы объявить функцию виртуальной, нужно добавить ключевое слово virtual: };

Если функция-член виртуальна, то при обращении к ней вызывается функция, определенная в динамическом типе объекта класса (или указателя, или ссылки на объект), для которого она вызвана. Однако для самих объектов класса статический и динамический тип - это одно и то же. Механизм виртуальных функций правильно работает только для указателей и ссылок на объекты.

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

NameQuery nq( lilacs );

правильно: но nq усечено до подобъекта Query

Рассмотрим следующий фрагмент кода:

Query qobject = nq;

Инициализация qobject переменной nq абсолютно законна: теперь qobject равняется подобъекту nq, который соответствует базовому классу Query, однако qobject не

который действует сейчас, был принят в 1986 году. Как вы думаете, почему была изменена исходная спецификация?

17.5. Виртуальные функции в базовом и производном классах

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



1 ... 290 291 292 [ 293 ] 294 295 296 ... 395

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