Архитектура Аудит Военная наука Иностранные языки Медицина Металлургия Метрология
Образование Политология Производство Психология Стандартизация Технологии


Порождение класса, контролирующего выход за границы массива



В функции try_array() из раздела 16.13, предназначенной для тестирования нашей предыдущей реализации шаблона класса Array, есть две инструкции:

int index = iA.find( find_val );

Type value = iA[ index ];

find() возвращает индекс первого вхождения значения find_val или -1, если значение в массиве не найдено. Этот код некорректен, поскольку в нем не проверяется, что не была возвращена -1. Поскольку -1 находится за границей массива, то каждая инициализация value может привести к ошибке. Поэтому мы создадим подтип Array, который будет контролировать выход за границы массива, – Array_RC и поместим его определение в заголовочный файл Array_RC.h:

#ifndef ARRAY_RC_H

#define ARRAY_RC_H

 

#include " Array.h"

 

template < class Type>

class Array_RC: public virtual Array< Type> {

public:

Array_RC( int sz = ArraySize )

      : Array< Type> ( sz ) {}

Array_RC( const Array_RC& r );

Array_RC( const Type *ar, int sz );

Type& operator[]( int ix );

};

 

#endif

Внутри определения производного класса каждая ссылка на спецификатор типа шаблона базового должна быть квалифицирована списком формальных параметров:

Array_RC( int sz = ArraySize )

  : Array< Type> ( sz ) {}

Такая запись неправильна:

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

Array_RC( int sz = ArraySize ): Array( sz ) {}

Единственное отличие поведения класса Array_RC от базового состоит в том, что оператор взятия индекса контролирует выход за границы массива. Во всех остальных отношениях можно воспользоваться уже имеющейся реализацией шаблона класса Array. Напомним, однако, что конструкторы не наследуются, поэтому в Array_RC определен собственный набор из трех конструкторов. Мы сделали класс Array_RC виртуальным наследником класса Array, поскольку предвидели необходимость множественного наследования.

Вот полная реализация функций-членов Array_RC, находящаяся в файле Array_RC.C (определения функций класса Array помещены в заголовочный файл Array.C, поскольку мы пользуемся моделью конкретизации шаблонов с включением, описанной в разделе 16.18):

#include " Array_RC.h"

#include " Array.C"

#include < assert.h>

 

template < class Type>

Array_RC< Type>:: Array_RC( const Array_RC< Type> & r )

 : Array< Type> ( r ) {}

 

template < class Type>

Array_RC< Type>:: Array_RC( const Type *ar, int sz )

 : Array< Type> ( ar, sz ) {}

 

template < class Type>

Type & Array_RC< Type>:: operator[]( int ix ) {

   assert( ix > = 0 & & ix < Array< Type>:: _size );

   return ia[ ix ];

}

Мы квалифицировали обращения к членам базового класса Array, например к _size, чтобы предотвратить просмотр Array до момента конкретизации шаблона:

Array< Type>:: _size;

Мы достигаем этого, включая в обращение параметр шаблона. Таким образом, имена в определении Array_RC разрешаются тогда, когда определяется шаблон (за исключением имен, явно зависящих от его параметра). Если встречается неквалифицированное имя _size, то компилятор должен найти его определение, если только это имя не зависит явно от параметра шаблона. Мы сделали имя _size зависящим от параметра шаблона, предварив его именем базового класса Array< Type>. Теперь компилятор не будет пытаться разрешить имя _size до момента конкретизации шаблона. (В определении класса Array_Sort мы приведем другие примеры использования подобных приемов.)

Каждая конкретизация Array_RC порождает экземпляр класса Array. Например:

Array_RC< string> sa;

конкретизирует параметром string как шаблон Array_RC, так и шаблон Array. Приведенная ниже программа вызывает try_array() (реализацию см. в разделе 16.13), передавая ей объекты подтипа Array_RC. Если все сделано правильно, то выходы за границы массивы будут замечены:

#include " Array_RC.C"

#include " try_array.C"

 

int main()

{

static int ia[] = { 12, 7, 14, 9, 128, 17, 6, 3, 27, 5 };

 

cout < < " конкретизация шаблона класса Array_RC< int> \n";

try_array( iA );

 

return 0;

}

После компиляции и запуска программа печатает следующее:

 

конкретизация шаблона класса Array_RC< int>

 

try_array: начальные значения массива

( 10 )< 12, 7, 14, 9, 128, 17

6, 3, 27, 5 >

 

try_array: после присваиваний

( 10 )< 128, 7, 14, 9, 128, 128

6, 3, 27, 3 >

 

try_array: почленная инициализация

( 10 )< 12, 7, 14, 9, 128, 128

6, 3, 27, 3 >

 

try_array: после почленного копирования

( 10 )< 12, 7, 128, 9, 128, 128

6, 3, 27, 3 >

 

try_array: после вызова grow

( 10 )< 12, 7, 128, 9, 128, 128

6, 3, 27, 3, 0, 0

0, 0, 0, 0 >

 

искомое значение: 5  возвращенный индекс: -1

Assertion failed: ix > = 0 & & ix < _size

 


Поделиться:



Последнее изменение этой страницы: 2019-04-09; Просмотров: 272; Нарушение авторского права страницы


lektsia.com 2007 - 2024 год. Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав! (0.016 с.)
Главная | Случайная страница | Обратная связь