Программирование >>  Унарные и бинарные операторы 

1 ... 22 23 24 [ 25 ] 26 27 28 ... 37


1 76 Глава 9. Операторные функции

Class А{ friend class В:

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

Ввод-вывод

До сих пор нам казалось, что объект cout и оператор волшебным образом знают, как выводить на экран объекты разных типов. Но дело, конечно не в волшебстве, а в том, что все эти объекты (строки, переменные int и double) стандартны, стоит попытаться вывести на экран объект класса conplex, о котором оператору ничего не известно, и компилятор сообщиг.

operator not implemented in type ostream for arguments of type complex in function mainO

Заметим, что дружба в С++ ие взаимна. Если класс В объявлен дружественным для А классом, то А ие становится от этого другом В. Для этого необходимо специальное объявление в классе В: friend class А.

Ввод-вывод 177

В этом сообщении, переводимом как оператор , принадлежащий классу ostream, не создан для аргументов типа cofrpl ех , есть важная информация. До сих пор мы не знали, к какому классу относится объект cout. Компилятор подсказывает нам: это класс ostream, и теперь у нас есть все необходимое, чтобы построить операторную функцию для вывода комплексных чисел.

Затруднение только в том, что оператор нельзя определить в созданном нами классе complex. Ведь для этого вьшод неременной нужно записать следуюгцим образом:

complex а: а cout:

Только при такой записи компилятор вызовет операторную функцию а.operator (), которая сможет вывести на экран комплексное число. Но в С++ принята другая запись cout а, что приводит к вызову одной из операторных функций (а именно cout.operator ()) класса ostream. В этом классе не предусмотрен вывод переменных нашего класса compl ex, что и вызьшает сообщение об ошибке. Значит, вывод на экран обычным для С++ способом (cout а;) требует либо изменения стандартного класса ostream, что нежелательно, либо использования внешней функции с двумя параметрами: первым должна быть ссылка на объект cout, вторым - объект класса complex. Если объявить операторную функцию дружественной классу conplex, то выглядеть она будет так, как показано в листинге 9.11.

Листинг 9.11

ostream& operator (ostream& stream, conplex a){ stream a. re . a. i m \n \n: return stream: }



Увеличение

Эта глава неожиданно оказалась длинной, но картина не будет полной, если пройти мимо унарных операторов ++ и --. Оператор ++ (для оператора - все аналогично) можетбыть определен в соответствуюп1емклассе, в этом случае операторной функщн! operator++() пе нужны параметры, достаточно ука.зателя па текущий объект this.

Попробуем переопределить оператор ++ для одного из известных нам классов. Объект этого класса должен быть таким, чтобы автоувеличение смотрелось так же естественно, как и для родных переменных типа int. Вряд лн стоит определять оператор++ для объектов класса complex, потому что для них увеличение пе имеет явного смысла (что увеличивать - реальную часть, мнимую часть или, быть может, обе?).

Поэтому вспомним о классе mycl оск, созданном в раз-Деле Богатые и бедные классы главы 8. Для объектов этого класса автоувеличепие вполне естественно: это перевод часов на секунду вперед. Соответствуюи1ая операторная функция показана в листинге 9.12.

Листинг 9.12

myclock & operator++(){ tickO; return *this:

Эта операторная функция сначала переводит стрелки на секунду вперед функцией tick(), а затем возвращает ссылку на измененный объект.

Очевидно, эта функция реализует префиксный оператор, ведь объект возвращается после перевода стрелок. Програ.мма, использующая такой оператор, показана в листинге 9.13.

Встретив в исходном тексте программы инструкции сопрТех а и cout а, компилятор вызовет операторную функцию из листинга 9.11 и передаст ей два аргумента: ссылку на объект cout (объект класса ostream) и объект а класса complex. Внутри операторной функции реализуются действия, характерные для оператора класса ostream: вывод чисел типа double и последовательностс11 символов.

Возвращает напш операторная функция ссылку на объект класса ostream - с тем, чтобы обеспечить вывод объектов по цепочке. Представим, что на экран выводятся несколько объектов:

cout А в С:

Если учесть, что оператор независимо от переопределений всегда выполняется слева направо, то сначала выполнится часть cout А. Если обтект А известен классу ostream, вызывается операторная функция cout.operator (A), которая возвращает ссылку, то есть другое имя объекта cout. Так что можно сказать, что после вывода А цепочка укоротится:

cout в <<:

Если объект В не известен классу ostream (потому, например, что это объект созданного нами типа complex), то вызывается внешняя операторная функция, такая как в листинге 9.11. Но поскольку она принимает и возвращает ссылку на ostream, порядок вывода не наруннп-ся: в зависимости от пта объектов будут вызьшатыя либо операторные функции класса ostream, либо внешние операторные функции, подобные той, что показана в листинге 9.11. И так будет до тех пор, пока не исчерпается список выводи.мых объектов.

Задача 9.3. Переопределите оператор для класса myclock, описанного в разделе Богатые и бедные классы главы 8.



рый должен увеличивать время после использования объекта. Если говорить об объектах класса myclock, то после выполнения следующих инструкций часы b должны показывать 10:59:30, а часы а - 10:59:31:

clock a(10.59.30).b: b=a++;

Но как компилятор поймет, что оператор постфиксный? Очевидно, нужен какой-то знак, отличаюпшй его от префиксного, и создатели С++ решили использовать для этого фиктивный целочисленный параметр (int) в определении операторной функции. Функция с таким параметром, показанная в листинге 9.14, реализует постфиксный оператор ++.

Листинг 9.14

myclock operator++(int){ myclock tmp=*this: tickO; return tmp:

Здесь сначала создается временная переменная tmp, где запоминается TCKyniee состояние объекта (this - указатель на текущий объект, оператор * превращает указатель в сам объект, а присваивание tnip=*this приводит к тому, что объект tmp запоминает состояние текущего обьекта). Далее стрелки объеюга *this переводятся на секунду вперед, и временный объект возвращается во внешний мир.

Обратите внимание, возвран1ается объект, а не ссылка на него. Это значит, что постфиксному оператору нельзя присвоить значение, он должен стоять справа от оператора присваивания (листинг 9.15). Листинг 9.15

#include <iostream.h> using namespace std; #include myclock4.h int main(){

Листинг 9.13

#inclucle <iostreani.h> using namespace std; #include myclockS.h int main(){ myclock a(10.59.Z9); for(int i=0; i<1000:i++)

cout ++a; return 0; }

В файле myclockS.h вместе с другими собственными функциями класса myclock есть и операторная функция для префиксного оператора ++. Кроме того, там определен и оператор . Если вам не удалось решить задачу 9.3, можете найти ответ в этом файле.

Программа из листинга 9.13 показывает 1000 значений времени, начиная с 10 часов 59 минут и 30 секунд, псггому что значение, установленное конструкторо.м, перед выводом на экран (10:59:29) увеличивается на секунду оператором ++.

Обратите внимание на то, что префиксный оператор, операторная функция для которого показана в листинге 9.12, возвращает ссылку на объект а. Как мы знаем, функции (а оператор - это специальная функция), возвращающей ссылку, можно присвоить значение, поэтому объекту а, если оператор ++ определен так, как в листинге 9.12, можно в полном соответствии со сгаи-дартом языка С++ присвоить значение ++а-Ь. Смысла в этом немного, ведь, несмотря на увеличение, объект а все равно станет равным Ь, но, по крайней мере, стандарт это разрешает. Можно также использовать цепочку операторов ++++а, в которой один оператор ++ передает ссылку на объект другому оператору ++, и в резул ьтате время увеличивается на две секунды.

Построив операторную функцию для префиксного оператора, перейдем к постфиксному оператору, кото-



1 ... 22 23 24 [ 25 ] 26 27 28 ... 37

© 2006 - 2025 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки.
Яндекс.Метрика