ArrayType::print( os );

вызывает функцию-член print() базового класса Array, конкретизированного одновременно с Array_Sort. Например:

Array_Sortstring sas;

конкретизирует типом string оба шаблона: Array_Sort и Array.

cout sas;

конкретизирует оператор вывода из класса Array, конкретизированного типом string, затем этому оператору передается строка sas. Внутри оператора вывода инструкция

ar.print( os );

приводит к вызову виртуального экземпляра print() класса Array_Sort, конкретизированного типом string. Сначала вызывается check_bit(), а затем статически вызывается функция-член print() класса Array, конкретизированного тем же типом. (Напомним, что под статическим вызовом понимается разрешение функции на этапе компиляции и – при необходимости – ее подстановка в место вызова.) Виртуальная функция обычно вызывается динамически в зависимости от фактического типа объекта, адресуемого ar. Механизм виртуализации подавляется, если она вызывается явно с помощью оператора разрешения области видимости, как в Array::print(). Это повышает эффективность в случае, когда мы явно вызываем экземпляр виртуальной функции базового класса из экземпляра той же функции в производном, например в print() из класса Array_Sort (см. раздел 17.5).

Функции-члены, определенные вне тела класса, помещены в файл Array_S.C. Объявление может показаться слишком сложным из-за синтаксиса шаблона. Но, если не считать списков параметров, оно такое же, как и для обычных классов:

template class Type

Array_SortType::

Array_Sort( const Array_SortType &as )

: ArrayType( as )

{

// замечание: as.check_bit() не работает!

// ---- объяснение см. ниже ...

if ( as.is_dirty() )

sort( 0, ArrayType::_size-1 );

clear_bit();

}

Каждое использование имени шаблона в качестве спецификатора типа должно быть квалифицировано полным списком параметров. Следует писать:

template class Type

Array_SortType::

Array_Sort( const Array_SortType &as )

а не

template class Type

Array_SortType::

Array_SortType( // ошибка: это не спецификатор типа

поскольку второе вхождение Array_Sort синтаксически является именем функции, а не спецификатором типа.

Есть две причины, по которым правильна такая запись:

if ( as.is_dirty() )

sort( 0, _size );

а не просто

as.check_bit();

Первая причина связана с типизацией: check_bit() – это неконстантная функция-член, которая модифицирует объект класса. В качестве аргумента передается ссылка на константный объект. Применение check_bit() к аргументу as нарушает его константность и потому воспринимается компилятором как ошибка.

Вторая причина: копирующий конструктор рассматривает массив, ассоциированный с as, только для того, чтобы выяснить, нуждается ли вновь созданный объект класса Array_Sort в сортировке. Напомним, однако, что член dirty_bit нового объекта еще не инициализирован. К началу выполнения тела конструктора Array_Sort инициализированы только члены ia и _size, унаследованные от класса Array. Этот конструктор должен с помощью clear_bit() задать начальные значения дополнительных членов и, вызвав sort(), обеспечить специальное поведение подтипа. Конструктор Array_Sort можно было бы инициализировать и по-другому:

// альтернативная реализация

template class Type

Array_SortType::

Array_Sort( const Array_SortType &as )

: ArrayType( as )

{

dirty_bit = as.dirty_bit;

clear_bit();

}

Ниже приведена реализация функции-члена grow().1 Наша стратегия состоит в том, чтобы воспользоваться имеющейся в базовом классе Array реализацией для выделения дополнительной памяти, а затем пересортировать элементы и сбросить dirty_bit:

template class Type

void Array_SortType::grow()

{

ArrayType::grow();

sort( 0, ArrayType::_size-1 );

clear_bit();

}

Так выглядит реализация двоичного поиска в функции-члене find() класса Array_Sort:

template class Type

int Array_SortType::find( const Type &val )

{

int low = 0;

int high = ArrayType::_size-1;

check_bit();

while ( low = high ) {

int mid = ( low + high )/2;

if ( val == ia[ mid ] )

return mid;

if ( val ia[ mid ] )

high = mid-1;

else low = mid+1;

}

return -1;

}

Перейти на страницу:

Похожие книги