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

1 ... 295 296 297 [ 298 ] 299 300 301 ... 395


void

base::

foo( int ival = base default value ) {

int real default value = 1024; настоее значение по умолчанию

if ( ival == base default value ) ival = real default value;

...

Здесь base default value - значение, согласованное между всеми классами иерархии, которое явно говорит о том, что пользователь не передал никакого аргумента.

void

derived::

foo( int ival = base default value ) {

int real default value = 204 8;

if ( ival == base default value ) ival = real default value;

...

Производный класс может быть реализован аналогично:

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

void doit and bedone( vector< Query* > *pvec ) {

...

for ( ; it != end it; ++it )

Query *pq = *it;

...

delete pq;

В данной функции мы применяем оператор delete:

Чтобы функция выполнялась правильно, применение delete должно вызывать деструктор того класса, на который указывает pq. Следовательно, необходимо объявить деструктор Query виртуальным:



class Query public:

virtual ~Query() { delete solution; }

...

Деструкторы всех производных от Query классов автоматически считаются виртуальными. doit and bedone() выполняется правильно.

Поведение деструктора при наследовании таково: сначала вызывается деструктор производного класса, в случае pq - виртуальная функция. По завершении вызывается деструктор непосредственного базового класса - статически. Если деструктор объявлен встроенным, то в точке вызова производится подстановка. Например, если pq указывает на объект класса AndQuery, то

delete pq;

приводит к вызову деструктора класса AndQuery за счет механизма виртуализации. После этого статически вызывается деструктор BinaryObject, а затем - снова статически - деструктор Query.

class Query {

public: ...

protected:

virtual ~Query();

...

class NotQuery : public Query {

public:

~NotQuery() ;

...

В следующей иерархии классов

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

int main() {

Query *pq = new NotQuery;

ошибка: деструктор является защищенным

delete pq;

которого вызывается:



class Query public:

irtual void eval() = 0;

...

чисто виртуальной: };

Реальное разрешение имени eval() происходит при построении отображения слов на вектор позиций. Если слово есть в тексте, то в отображении будет его вектор позиций. В нашей реализации вектор позиций, если он имеется, передается конструктору NameQuery вместе с самим словом. Поэтому в классе NameQuery функция eval() пуста.

Однако м1 не можем унаследовать чисто виртуальную функцию из Query. Почему? Потому что NameQuery - это конкретный класс, объекты которого разрешается создавать в приложении. Если бы мы унаследовали чисто виртуальную функцию, то он стал бы абстрактным классом, так что создать объект такого типа не удалось бы. Поэтому мы

class NameQuery : public Query { public:

virtual void eval() {} ...

объявим eval() пустой функцией: };

Для запроса NotQuery от1скиваются все строки текста, где указанное слово отсутствует. Для таких строк в член loc класса NotQuery помещаются все нары (строка, колонка). Наша реализация выглядит следующим образом:

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

17.5.6. Виртуальная функция eval()

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



1 ... 295 296 297 [ 298 ] 299 300 301 ... 395

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