Г. Шилтд - Самоучитель C++ (PDF) (1114887), страница 26
Текст из файла (страница 26)
О дружественных оператор -функциях будет рассказано далее вэтой главе.Здесь представлена основная форма оператор -функции — члена класса:во-звращаемБш_:гил ш*я_хласса: : opera tor # (список аргументов){// выполняемая операцияЧасто типом возвращаемого значения оператор -функции является класс, длякоторого она определена. (Хотя оператор- функция может возвращать данные любого типа.) В представленной общей форме оператор -функции вме-Глава 6.
Введение в перегрузку операторов177сто знака # нужно подставить перегружаемый оператор. Например, если перегружается оператор +, то у функции должно быть имя operator*. Содержание списка список-аргументов зависит от реализации оператор-функциии от типа перегружаемого оператора.Следует запомнить два важных ограничения на перегрузку операторов. Вопервых, нельзя менять приоритет операторов.
Во-вторых, нельзя менятьчисло операндов оператора. Например, нельзя перегрузить оператор / так,чтобы в нем использовался только один операнд.Большинство операторов C++ можно перегружать. Ниже представлены тенесколько операторов, которые перегружать нельзя:Кроме того, нельзя перегружать операторы препроцессора. (Оператор .* является сугубо специальным и в книге не рассматривается.)Запомните, что в C++ понятие оператора трактуется очень широко: в этопонятие входят оператор индексирования [], оператор вызова функции (),операторы new и delete, операторы .
(точка) и -> (стрелка). Однако в даннойглаве мы коснемся более обычных операторов.Оператор-функции, за исключением оператора —, наследуются производнымклассом. Тем не менее для производного класса тоже можно перегрузить любой выбранный оператор (включая операторы, уже перегруженные в базовомклассе).Вы уже пользовались двумя перегруженными операторами: « и », которые перегружались для реализации ввода/вывода. Как уже упоминалось, перегрузка этих операторов для реализации ввода/вывода не мешает имвыполнять свои традиционные функции левого и правого сдвига.Хотя допустимо иметь оператор-функцию для реализации любого действия связанного или нет с традиционным употреблением оператора — лучше, еслидействия перегружаемых операторов остаются в сфере их традиционного использования.
При создании перегружаемых операторов, для которых этотпринцип не поддерживается, имеется риск существенного снижения читабельности программ. Например, перегрузка оператора / так, чтобы 300 раззаписать в дисковый файл фразу "Мне нравится C++", является явным злоупотреблением перегрузкой операторов.Несмотря на вышесказанное, иногда может потребоваться использовать какой-либо оператор нетрадиционным образом.
Типичным примером этого какраз и являются перегруженные для ввода/вывода операторы « и ». Однакодаже в этом случае, левые и правые стрелки обеспечивают визуально понятный смысл их значения. Поэтому, даже если вам очень хочется перегрузитькакой-нибудь оператор нестандартным способом, лучше приложите дополнительные усилия и постарайтесь воспользоваться каким-нибудь более подходящим оператором.И последнее, оператор-функции не могут иметь параметров по умолчанию.178Самоучитель C++6.2.
Перегрузка бинарных операторовКогда оператор-функция — член класса перегружает бинарный оператор, уфункции будет только один параметр. Этот параметр получит тот объект,который расположен справа от оператора. Объект слева генерирует вызовоператор-функции и передается неявно, с помощью указателя this.Важно понимать, что для написания оператор-функций имеется множествовариантов. Примеры, показанные здесь и в других местах главы, не являются исчерпывающими, хотя они иллюстрируют несколько наиболее общихтехнических приемов.Примеры1. В следующей программе перегружается оператор + относительно классаcoord. Этот класс используется для поддержания координат X,Y.// Перегрузка оператора 4 относительно класса coord^include <iostream>using namespace std;class coord {int x,y; // значения координатpublic:coord () { x = 0; y= 0; }coord{int i, int j) { x = i; у = j; }void get_xy(int &i, int £j ) { i = x; j = y; }coord operator-*- (coord ob2) ;I / Перегрузка оператора + относительно класса coordcoord coord: :operator+ (coord ob2){coord temp;temp.x = x +ob2.x;temp.
у = у +оЬ2.у;return temp;int main ()coord ol (10, 10), o2(5, 3), o3;int x, y;o3 = ol + o2; // сложение двух объектов// вызов функции operator-*- ()Глава 6. Введение в перегрузку операторов179оЗ.get_xy(x, у ) ;cout « "(01 + о2) X: " « х « ", Y: " « у « "\п";return 0;)После выполнения программы на экран выводится следующее:.(ol + о2) X: 15, Y: 13Давайте внимательно рассмотрим программу.
Функция operator+() возвращает объект типа coord, в котором сумма координат по оси X находится в переменной х, а сумма координат по оси Y — в переменной у. Отметьте, чтовременный объект temp используется внутри функции operator+() для хранения результата и является возвращаемым объектом. Отметьте также, что ниодин из операндов не меняется. Назначение переменной temp легко понять.В данной ситуации (как и в большинстве ситуаций) оператор + был перегружен способом, аналогичным своему традиционному арифметическому использованию. Поэтому и было важно, чтобы ни один из операндов неменялся. Например, когда вы складываете 10-И, результат равен 14, но ни10, ни 4 не меняются.
Таким образом, временный объект необходим для хранения результата.Смысл того, что функция operator+О возвращает объект типа coord, состоитв том, что это позволяет использовать результат сложения объектов типаcoord в сложном выражении. Например, инструкцияоЗ = ol + о2;правильна только потому, что результат выполнения операции ol + о2 является объектом, который можно присвоить объекту оЗ. Если бы возвращаемым значением был объект другого типа, то эта инструкция была бынеправильна.
Более того, возвращая объект типа coord, оператор сложениядопускает возможность существования строки, состоящей из несколькихсложений. Например, следующая инструкция вполне корректна:оЗ = ol + о2 + ol + оЗ;Хотя у вас будут ситуации, в которых понадобится оператор-функция, возвращающая нечто иное, чем объект класса, для которого она определена,большинство создаваемых вами оператор-функций будут возвращать именнотакие объекты.
(Основное исключение из этого правила связано с перегрузкой операторов отношения и логических операторов. Эта ситуация исследуется в разделе 6.3 "Перегрузка операторов отношения и логическихоператоров" далее в этой главе.)Последнее замечание по этому примеру. Поскольку объект типа coord является возвращаемым значением оператор-функции, то следующая инструкциятакже совершенно правильна:(ol 4 о2).get x y ( x , у ) ;180_СамоучительC++Здесь временный объект, возвращаемый функцией operator+(), используетсянепосредственно.
Естественно, что после выполнения этой инструкции временный объект удаляется.2. В следующей версии предыдущей программы относительно класса coord перегружаются операторы — и =.// Перегрузка операторов +, — и = относительно класса coord^include <iostream>using namespace std;class coord {int x, у; // значения координатpublic:coord () { x = 0; y= 0; }coord (int i, int j) { x = i; у = j ; }void get_xy(int &i, int &j} { i = x; j = y; }coord operator-f (coord ob2) ;coord operator- (coord ob2);coord operator= (coord ob2) ;// Перегрузка оператора + относительно класса coordcoord coord: :operator+ (coord ob2)(coord temp;terap.x = x + ob2.x;temp, у = у -f ob2.y;return temp;}// Перегрузка оператора — относительно класса coordcoord coord: : operator- (coord ob2}{coord temp;temp .
x = x - ob2 . x ;temp. у = у — ob2.y;return temp;// Перегрузка оператора = относительно класса coordcoord coord: :operator=( coord ob2){x = ob2 . x ;у = ob2.y;Глава6.Введениевперегружуоператоров_181return *this; // возвращение объекта,// которому присвоено значение>,,int main{){coord ol (10, 10), o2(5, 3), оЗ;int x, y;o3 = ol + o2; // сложение двух объектов// вызов функции operator* ()o3.get_xy !x, у) ;cout « "(ol + о2) X: " « x « ", Y: " « у « "\n";•оЗ = ol — о2; // вычитание двух объектов// вызов функции operator- ()o3.get_xy (х, у) ;cout « " (ol - о2) X: " « х « ", Y: " « у « "\п";оЗ = ol; // присваивание объекта- вызов функции operator= ( }o3.get_xy (х, у) ;cout « "(оЗ = ol) X: " « х « ", Y: " « у « "\п";return 0;Реализация функции operator— () похожа на реализацию функции operator+().Однако она иллюстрирует ту особенность перегрузки операторов, где важенпорядок следования операндов.
При создании функции operator+() порядокследования операндов значения не имел. (То есть А+В тождественно В+А.)Однако результат операции вычитания зависит от порядка следования операндов. Поэтому, чтобы правильно перегрузить оператор вычитания, необходимо вычесть правый операнд из левого. Поскольку левый операндгенерирует вызов функции operator— (), порядок вычитания должен быть следующим:х — оЬ2 . х ;При перегрузке бинарного оператора левый операнд передается функции неявно, аправый оператор передается функции в качестве аргумента.Теперь рассмотрим оператор-функцию присваивания.
В первую очередь необходимо отметить, что левый операнд (т. е. объект, которому присваиваетсязначение) после выполнения операции меняется. Здесь сохраняется обычныйсмысл присваивания. Во-вторых, функция возвращает указатель *this. Это182Самоучительпроисходит потому, что функция operator=() возвращает тот объект, которому присваивается значение. Таким образом удается выстраивать операторыприсваивания в цепочки. Как вы уже должны знать, в C++ следующая инструкция синтаксически правильна (и на практике вполне обычна):a = b = c = d = 0 ;Возвращая указатель *this, перегруженный оператор присваивания дает возможность подобным образом выстраивать объекты типа coord.
Например,представленная ниже инструкция вполне корректна:оЗ « о2 = ol;Запомните, нет правила, требующего, чтобы перегруженная операторфункция присваивания возвращала объект, полученный в результате присваивания. Однако если вы хотите перегрузить оператор = относительнокласса, то, как и в случае присваивания встроенных типов данных, он должен возвращать указатель *this.3. Имеется возможность перегрузить оператор относительно класса так, чтоправый операнд будет объектом встроенного типа, например, целого, а необъектом того класса, членом которого является оператор-функция.