Выбрать главу

#include cassert

int IntArray::operator[] (int index)

{

assert (index = 0 index _size);

return ia[index];

}

Обычно для проектируемого класса перегружают операции присваивания, операцию сравнения на равенство, возможно, операции сравнения по величине и операции ввода/вывода. Как и перегруженных функций, перегруженных операторов, отличающихся типами операндов, может быть несколько. К примеру, можно создать несколько операций присваивания объекту значения другого объекта того же самого или иного типа. Конечно, эти объекты должны быть более или менее “похожи”. (Подробно о перегрузке операций мы расскажем в главе 15, а в разделе 3.15 приведем еще несколько примеров.)

Определения класса, различных относящихся к нему констант и, быть может, каких-то еще переменных и макросов по принятым соглашениям помещаются в заголовочный файл, имя которого совпадает с именем класса. Для класса IntArray мы должны создать заголовочный файл IntArray.h. Любая программа, в которой будет использоваться класс IntArray, должна включать этот заголовочный файл директивой препроцессора #include.

По тому же самому соглашению функции-члены класса, определенные вне его описания, помещаются в файл с именем класса и расширением, обозначающим исходный текст С++ программы. Мы будем использовать расширение .С (напомним, что в разных системах вы можете встретиться с разными расширениями исходных текстов С++ программ) и назовем наш файл IntArray.C.

Упражнение 2.5

Ключевой особенностью класса С++ является разделение интерфейса и реализации. Интерфейс представляет собой набор операций (функций), выполняемых объектом; он определяет имя функции, возвращаемое значение и список параметров. Обычно пользователь не должен знать об объекте ничего, кроме его интерфейса. Реализация скрывает алгоритмы и данные, нужные объекту, и может меняться при развитии объекта, никак не затрагивая интерфейс. Попробуйте определить интерфейсы для одного из следующих классов (выберите любой):

(a) матрица

(b) булевское значение

(c) паспортные данные человека

(d) дата

(e) указатель

(f) точка

Упражнение 2.6

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

Упражнение 2.7

В предыдущих упражнениях вы практически полностью определили интерфейс выбранного вами класса. Попробуйте теперь написать программу, использующую ваш класс. Удобно ли пользоваться вашим интерфейсом? Не хочется ли Вам пересмотреть спецификацию? Сможете ли вы сделать это и одновременно сохранить совместимость со старой версией?

2.4. Объектно-ориентированный подход

Вспомним спецификацию нашего массива в предыдущем разделе. Мы говорили о том, что некоторым пользователям может понадобиться упорядоченный массив, в то время как большинство, скорее всего, удовлетворится и неупорядоченным. Если представить себе, что наш массив IntArray упорядочен, то реализация таких функций, как min(), max(), find(), должна отличаться от их реализации для массива неупорядоченного большей эффективностью. Вместе с тем, для поддержания массива в упорядоченном состоянии все прочие функции должны быть сильно усложнены.

Мы выбрали наиболее общий случай – неупорядоченный массив. Но как же быть с теми немногочисленными пользователями, которым обязательно нужна функциональность массива упорядоченного? Мы должны специально для них создать другой вариант массива?

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

Да, мы можем удовлетворить и тех и других, создав для каждой группы пользователей свой, немного модернизированный, вариант IntArray. Более того, его даже не слишком трудно сделать, поскольку мы старались создать хорошую реализацию и необходимые изменения затронут совсем небольшие участки кода. Итак, копируем исходный текст, вносим необходимые изменения в нужные места и получаем три класса: