Протестируем нашу реализацию класса Array_Sort с помощью функции try_array(). Показанная ниже программа тестирует шаблон этого класса для конкретизаций типами int и string:
#include "Array_S.C"
#include "try_array.C"
#include string
main()
{
static int ia[ 10 ] = { 12,7,14,9,128,17,6,3,27,5 };
static string sa[ 7 ] = {
"Eeyore", "Pooh", "Tigger",
"Piglet", "Owl", "Gopher", "Heffalump"
};
Array_Sortint iA( ia,10 );
Array_Sortstring SA( sa,7 );
cout "eiie?aoecaoey eeanna Array_Sortint"
endl;
try_array( iA );
cout "eiie?aoecaoey eeanna Array_Sortstring"
endl;
try_array( SA );
return 0;
}
При конкретизации типом string после компиляции и запуска программа печатает следующий текст (обратите внимание, что попытка вывести элемент с индексом -1 заканчивается крахом):
конкретизация класса Array_Sortstring
try_array: начальные значения массива
( 7 ) Eeyore, Gopher, Heffalump, Owl, Piglet, Pooh
Tigger
try_array: после присваиваний
( 7 ) Eeyore, Gopher, Owl, Piglet, Pooh, Pooh
Pooh
try_array: почленная инициализация
( 7 ) Eeyore, Gopher, Owl, Piglet, Pooh, Pooh
Pooh
try_array: после почленного копирования
( 7 ) Eeyore, Piglet, Owl, Piglet, Pooh, Pooh
Pooh
try_array: после вызова grow
( 7 ) empty, empty, empty, empty, Eeyore, Owl
Piglet, Piglet, Pooh, Pooh, Pooh
искомое значение: Tigger возвращенный индекс: -1
Memory fault (coredump)
После почленного копирования массив не отсортирован, поскольку виртуальная функция вызывалась через объект, а не через указатель или ссылку. Как было сказано в разделе 17.5, в таком случае вызывается экземпляр функции из класса именно этого объекта, а не того подтипа, который может находиться в переменной. Поэтому функция sort() никогда не будет вызвана через объект Array. (Разумеется, мы реализовали такое поведение только в целях демонстрации.)
18.6.3. Класс массива с множественным наследованием
Определим отсортированный массив с контролем выхода за границы. Для этого можно применить множественное наследование от Array_RC и Array_Sort. Вот как выглядит наша реализация (напомним еще раз, что мы ограничились тремя конструкторами и оператором взятия индекса). Определение находится в заголовочном файле Array_RC_S.h:
#ifndef ARRAY_RC_S_H
#define ARRAY_RC_S_H
#include "Array_S.C"
#include "Array_RC.C"
template class Type
class Array_RC_S : public Array_RCType,
public Array_SortType
{
public:
Array_RC_S( int sz = ArrayType::ArraySize )
: ArrayType( sz )
{ clear_bit(); }
Array_RC_S( const Array_RC_S &rca )
: ArrayType( rca )
{ sort( 0,ArrayType::_size-1 ); clear_bit(); }
Array_RC_S( const Type* arr, int sz )
: ArrayType( arr, sz )
{ sort( 0,ArrayType::_size-1 ); clear_bit(); }
Type& operator[]( int index )
{
set_bit();
return Array_RCType::operator[]( index );
}
};
#endif
Этот класс наследует две реализации каждой интерфейсной функции Array: из Array_Sort и из виртуального базового класса Array через Array_RC (за исключением оператора взятия индекса, для которого из обоих базовых классов наследуется замещенный экземпляр). При невиртуальном наследовании вызов find() был бы помечен компилятором как неоднозначный, поскольку он не знает, какой из унаследованных экземпляров мы имели в виду. В нашем случае замещенным в Array_Sort экземплярам отдается предпочтение по сравнению с экземплярами, унаследованными из виртуального базового класса через Array_RC (см. раздел 18.5.4). Таким образом, при виртуальном наследовании неквалифицированный вызов find() разрешается в пользу экземпляра, унаследованного из класса Array_Sort.