Г. Шилтд - Самоучитель C++ (DJVU) (1114955), страница 30
Текст из файла (страница 30)
Самоучитель С++ Чтобы понять, как работает оператор Ц, представим, что объект О индекси- руется следующим образом: 0 [91 Этот индекс транслируется в вызов функции орега1огЦО: О.орегагог(](Э) Таким образом, значение выражения внутри оператора индексирования явно передается функции орега[огЦО в качестве параметра. При этом указатель г]ив будет ссылаться на объект О, являющийся источником вызова. 1. В следующей программе объявляется состоящий из гьяти целых массив аггау(уре. Каждый элемент массива инициализируется конструктором. Перегруженная функция орегагогЦО возвращает элемент, заданный ее параметром.
() ьпс1п<(е <1ояг гаага» пягпд пашеярасе ясо; сопяс гпп ядие = 5," с1аяя аггаусуре ( гпс а [Я12е]г рпЬ11с. аггаугуре () ( гп 3. г" гог (1=о; 1<этик; 1++) а[1) гпс орегасог [] (1пе 1) ( гепигп а[1]; ) пи ваьп ( ) аггаугуре оЬ! [ггт 1; Гог(1=0; )<Я]УЕ; 1++) сопг « оЬ[1] « " "р гегпгп 0; В результате работы программы на экран выводится следующее: 012 3 4 Глава В. Введение в перегрузку операторов 109 В этом и остальных примерах инициализация массива а с помощью конструктора выполнена исключительно в иллюстративных целях и на самом деле не требуется. 2.
Имеется возможность перегрузить функцию оуега[агЦ() так, чтобы в инструкции присваивания оператор Ц можно было располагать как слева, так и справа от оператора =. Для этого возвратите ссылку на индексируемый элемент. Следующая программа иллюстрирует такой подход. п(пс!иг1с <1оат.теав> ив1па пагпеврасе всг() сопвС (пс $(ХЕ = 5; с1авв агтаусуре 1пг а [Вгик]> рпЬ11с: ап ау1урс () ( тпт 1; гог (1=ог 1<31ЯЕ; 1++) а [1] (п1 аорегасог[] (з.п 1) ( гетпгп а [1.]; [п1 иа Еп ( ) ( ап аугуре оЬ; 1пт 1; аког (1=0,' 1<К1ХЕ; 1+~-) сонг « оЬ [1] « СОПГ « "~П" 1 // добавление значения 1О к каждому элементу массива аког(1=01 1<$1УЕ; 1++) оЬ[1] = оЬ[1]+10; // оператор П слева от оператора Хог(1-0; 1<МХЕ; 1++) сопт « оЬ[Ц « " "1 гегпгп 0; В результате работы программы на экран выводится следующее: 01234 10 11 12 13 14 Поскольку теперь функция орега[ог[]О возвращает ссылку на элемент массива с индексом [, то для изменения этого элемента оператор [~ можно рас- гоо Самоучитель С.н- положить слева в инструкции присваивания.
(Естественно, что как и прежде его можно располагать справа.) Таким образом, с объектами типа аггау[уре можно обращаться так же, как и с обычными массивами. 3. Перегрузка оператора [] дает возможность по-новому взглянуть на задачу индексирования безопасного массива. Ранее в этой книге мы рассматривали простейший способ реализации безопасного массива, в котором для доступа к элементам массива использовались функции яе1() и рв1(). Перегрузка оператора [] позволит нам теперь создать такой массив гораздо проще. Вспомните, что безопасный массив — это массив, который инкапсулирован в классе, и при этом класс обеспечивает контроль границ массива.
Такой подход предотвращает нарушение границ массива. Благодаря перегрузке оператора Ц, работать с безопасным массивом можно так же, как с обычным. Для создания безопасного массива просто реализуйте в функции орега1ог[]0 контроль границ. Кроме этого, функция орега1огЦ() должна возврашать ссылку на индексируемый элемент.
Например, в представленном ниже примере в предыдущую программу добавлен контроль границ массива, что позволяет при нарушении границ генерировать соответствующую ошибку. // Пример безопасного массива )) ьпс1пде <ьовсгеа~а> $1пс1цг)е <свтг)11)з> цвьпд пагпеарасе зтд; сонат шг ИЛЕ = 5; с)аьв аггаутуре 1пг а [Я12Е); ри)>1тс: аггаугурс () [гтт 1; Гог !1=от 1<Я1ее; 1++) а[ ) ) )пг аорегасог[) [1пс [); // Обеспечение контроля границ для массива типа аггаутуре )пг Йаггаугуре:: орегасог [),'з пс )) 1= [1<О ~ ) 1>Я1ЛЕ-1) ) сонг « "1пэначение индекса соцт « ) « " находится за пределами границ массива. ~п" ех)Г [1); ) гегцгп а [1); Глава б.
Введение в перегрузкуоператороа [пг тпа1п О аггаувуре оЬ; гпп 1,' Здесь проблем нет Гог[1=01 1(етее1 1++1 сопб « оЬ[11 << /* А здесь при выполнении программы генерируется оьибка, поскольку значение ЯХЕЕ+100 не входит в заданный длапазон *т оЬ[Б1УЕ~-1001 = 99; тт Овмбка!!! геспгп 0; Благодаря контролю границ, реализованному в функции орегатотЦ(), при выполнении инструкции оь[31Уеч-1001 = 99; программа завершится еще до того, как будет повреждена какая-либо ячейка памяти. Поскольку перегрузка оператора [[ позволяет создавать безопасные массивы, которые выглядят и функционируют так же, как самые обычные массивы, их можно безболезненно добавить в вашу программную среду.
Однако будьте внимательны. Безопасный массив увеличивает расход ресурсов, что не во всех ситуациях может оказаться приемлемым. Фактически, именно из-за непроизводительного расхода ресурсов в С++ отсутствует встроенный контроль границ массивов. Тем не менее, в тех приложениях, в которых желательно обеспечить целостность границ, реализация безопасного массива будет лучшим решением. 1. Переделайте пример 1 из раздела 6.6 так, чтобы относительно класса в[г[уре перегрузить оператор [1. Этот оператор должен возврашать символ по заданному индексу. Кроме этого, необходима возможность задавать оператор Ц в левой части инструкции присваивания. Покажите, что ваша программа работает.
2. Измените ваше решение упражнения 1 из раздела 6.6 так, чтобы оператор [[ использовать для индексирования динамического массива. То есть замените функции детО и ри1() оператором [1. Самоучитель С++ 202 Теперь вам необходимо выполнить следующие упражнения и ответить на вопросы: 1. Перегрузите операторы сдвига >> и « относительно класса соотг так, чтобы стали возможными следующие типы операций: оЬ сс ).пЬеоег оЬ » заведет Удостоверьтесь, что ваши операторы действительно сдвигают значения х и у на заданное количество разрядов. 2.
Пусть дан класс с1ааа сжатее с1 ( зпс х, у, х; риЬ).~с: стссее с)1).ае 1, 1ос 1, )пс )с) х=);у=бтх=.)с; сьхее с)1) 1 х = О; у = о; с = о; чоЫ 0ес (1ос ьз., 1пс х3, )ос ь)с) )=х; ) =у; /с=х; ) Перегрузите для этого класса операторы +, —, ++ и —. (Для операторов инкремента и декремента перегрузите только префиксную форму.) 3. Измените ваше решение вопроса 2 так, чтобы в оператор-функциях вместо параметров-значений использовать параметры-ссылки. ~Подсказка.
Для операторов инкремента и декремента вам потребуются дружественные функции.) 4. Чем действие дружественной оператор-функции отличается от действия оператор-функции — члена класса? 5. Объясните, почему может потребоваться перегрузка оператора присваи- вания. 6. Может ли функция арега1ог=О быть дружественной? 7. Перегрузите оператор + для класса атее й из вопроса 2 так, чтобы иметь возможность выполнять следующие типы операций: Глава 6. Введение в перегрузкуоператоров оЬ -~- ~пи 1п1 -~- оЬ; 8. Перегрузите операторы ==, != и ~~ относительно класса аггее д из вопроса 2.
9. Приведите главный довод в пользу перегрузки оператора Ц, В этом разделе проверяется, хорошо ли вы усвоили материал этой и предыдущих глав. 1. Создайте класс згггуре, который допускает следующие типы операции: Конкатенацию строк с помощью оператора + ° Присваивание строк с помощью оператора = ° Сравнение строк с помощью операторов <, > и== Можете пользоваться строками фиксированной длины. На первый взгляд это может показаться непростой задачей, но, немного подумав (и поэкспериментировав), вы должны справиться. Глава 7 Наследование Ранее в этой книге вы познакомились с концепцией наследования. Сейчас пришло время осветить эту тему более детально.
Наследование — это один из трех базовых принципов ООР, и потому является одним из важнейших инструментов С++. В С++ наследование используется не только для поддержки иерархии классов, но, как вы узнаете из главы 10, и для поддержки другого важнейшего инструмента ООР— полиморфизма. Материал, который приведен в этой главе, включает в себя следующие темы: управление доступом к базовому классу, спецификатор доступа рго1ес1ей, множественное наследование, передача аргументов конструкторам базового класса, виртуальные базовые классы.
Перед тем как продолжить, необходимо правильно ответить на следующие вопросы и сделать упражнения.- 1. Теряет ли оператор при перегрузке что-либо из своей исходной функ- циональности? 2. Нужно ли перегружать оператор относительно определенного пользова- телем типа данных, например, класса? 3. Можно ли изменить приоритет перегруженного оператора? Можно ли изменить количество операндов? 4. Дана следующая, почти законченная программа, добавьте недостающие оператор-функции: $1пс1пг[е <гоа~геага> па[па пагпеарасе агЖ с)аеа аггау [пг пгааа [10 ) рггЫ1 с: аггау(1; Самоучитель С++ чей яее(1пт. п[10]); воз с[ вЬои () т аттау орега~от+(ашгау оЬ2); аттау орегаеог-(авхау оЬ2) ) 1пс орегаЬог==(ахгау оЬ2); ахтауттаггау() [ 1пс 1; ~от(1 = 0; 1 < 10; 1++) пошта[1) — 0 чоуо актау::вее (1п1 *и) ( 1пс 1; [от([ = 0; [ < 10; [++) пвтав[1] = п[1]; ~оЫ аткау:: в)тон () 1пт 1т йов(1 = 0; ' < 10) 1~+) соус « птттвв[1] « соус « "М"т Впишите оператор-4>ункпии 1пс тваап[) т автау о1, о2, оЗ; 1пе 1[10] = (1, 2, 3, 4, 5, б, 7, 8, 9, 10 о1.
вее (1); о2.вей(1) т оЗ о1 + о2т оЗ.вЬои()т оЗ =о1— оЗ.впотт() оЗ; 1~(о1==о2 е1ве сопс 1й(о1==оЗ е1ве соие тесаков 0; сон" « "о1 равно о2~п" т « "о1 не равна о2~в"; сочв « "о1 равно оЗ~,п"; « "о1 не равно о31п" т Глава 7. Наследование Перегруженный оператор + должен поэлементно складывать оба операнда. Перегруженный оператор — должен вычитать все элементы правого операнда из элементов левого.