( 5 ) 14.6, 14.6, 14.6, 9.8, 7.9
try_array: после вызова grow
( 8 ) 14.6, 14.6, 14.6, 9.8, 7.9, 0, 0, 0
искомое значение: 128 возвращенный индекс: -1
значение элемента с этим индексом: 3.35965e-322
Выход индекса за границу массива приводит к тому, что последнее напечатанное программой значение неверно. Конкретизация шаблона Array типом string заканчивается крахом программы:
template Arraystring class
try_array: начальные значения массива
( 7 ) Eeyore, Pooh, Tigger, Piglet, Owl, Gopher, Heffalump
try_array: после присваиваний
( 7 ) Tigger, Pooh, Tigger, Tigger, Owl, Gopher, Eeyore
try_array: почленная инициализация
( 7 ) Tigger, Pooh, Tigger, Tigger, Owl, Gopher, Eeyore
try_array: после почленного копирования
( 7 ) Tigger, Tigger, Tigger, Tigger, Owl, Gopher, Eeyore
try_array: после вызова grow
( 11 ) Tigger, Tigger, Tigger, Tigger, Owl, Gopher, Eeyore, пусто , пусто , пусто , пусто
искомое значение: Heffalump возвращенный индекс: -1
Memory fault (coredump)
Упражнение 16.11
Измените шаблон класса Array, убрав из него функции-члены sort(), find(), max(), min() и swap(), и модифицируйте шаблон try_array() так, чтобы она вместо них пользовалась обобщенными алгоритмами (см. главу 12).
2011-09-05 16:08:36 Алексей
Спасибо за статью. Было интересно и полезно.
V. Объектно-ориентированное программирование
Объектно-ориентированное программирование расширяет объектное программирование, вводя отношения тип-подтип с помощью механизма, именуемого наследованием. Вместо того чтобы заново реализовывать общие свойства, класс наследует данные-члены и функции-члены родительского класса. В языке C++ наследование осуществляется посредством так называемого порождения производных классов. Класс, свойства которого наследуются, называется базовым, а новый класс - производным. Все множество базовых и производных классов образует иерархию наследования.
Например, в трехмерной компьютерной графике классы OrthographicCamera и PerspectiveCamera обычно являются производными от базового Camera. Множество операций и данных, общее для всех камер, определено в абстрактном классе Camera. Каждый производный от него класс реализует лишь отличия от абстрактной камеры, предоставляя альтернативный код для унаследованных функций-членов либо вводя дополнительные члены.
Если базовый и производный классы имеют общий открытый интерфейс, то производный называется подтипом базового. Так, PerspectiveCamera является подтипом класса Camera. В C++ существует специальное отношение между типом и подтипом, позволяющее указателю или ссылке на базовый класс адресовать любой из производных от него подтипов без вмешательства программиста. (Такая возможность манипулировать несколькими типами с помощью указателя или ссылки на базовый класс называется полиморфизмом.) Если дана функция:
void lookAt( const Camera *pCamera );
то мы реализуем lookAt(), программируя интерфейс базового класса Camera и не заботясь о том, на что указывает pCamera: на объект класса PerspectiveCamera, на объект класса OrthographicCamera или на объект, описывающий еще какой-то вид камеры, который мы пока не определили.
При каждом вызове lookAt() ей передается адрес объекта, принадлежащего к одному из подтипов Camera. Компилятор автоматически преобразует его в указатель на подходящий базовый класс:
// правильно: автоматически преобразуется в Camera*
OrthographicCamera ocam;
lookAt( &ocam );
// ...
// правильно: автоматически преобразуется в Camera*
PerspectiveCamera *pcam = new PerspectiveCamera;
lookAt( pcam );
Наша реализация lookAt() не зависит от набора подтипов класса Camera, реально существующих в приложении. Если впоследствии потребуется добавить новый подтип или исключить существующий, то изменять реализацию lookAt() не придется.
Полиморфизм подтипов позволяет написать ядро приложения так, что оно не будет зависеть от конкретных типов, которыми мы манипулируем. Мы программируем открытый интерфейс базового класса придуманной нами абстракции, пользуясь только ссылками и указателями на него. При работе программы будет определен фактический тип адресуемого объекта и вызвана подходящая реализация открытого интерфейса.
Нахождение (или разрешение) нужной функции во время выполнения называется динамическим связыванием (dynamic binding) (по умолчанию функции разрешаются статически во время компиляции). В C++ динамическое связывание поддерживается с помощью механизма виртуальных функций класса. Полиморфизм подтипов и динамическое связывание формируют основу объектно-ориентированного программирования, которому посвящены следующие главы.