Г. Шилтд - Самоучитель C++ (PDF) (1114887), страница 28
Текст из файла (страница 28)
Как вы знаете, знак минус в C++ является как бинарным, так и унарнымоператором. Вы, наверное, хотели бы знать, как его можно перегрузить относительно создаваемого вами класса так, чтобы оператор сохранил оба эти качества. Реальное решение достаточно элементарно: просто перегрузите егодважды, один раз как бинарный оператор, а второй — как унарный. Программа, реализующая этот прием, показана ниже:// Перегрузка оператора — относительно класса coord^include <iostream>using namespace std;class coord {int x, у; // значения координатpublic:coord (J { 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); // бинарный минусcoord operator- (); // унарный минус}t/ / Перегрузка оператора — относительно класса coordcoord coord: : operator- (coord ob2)1coord temp;terap.x = x — ob2.x;temp.
у = у — ob2.y;return temp;// Перегрузка унарного оператора — для класса coordcoord coord: : operator- ( )Глава 6. Введение в перегрузку операторов__189return *this;}int main (){coord ol(10, 10), o 2 ( 5 , 7 ) ;int x, y;ol = ol — o2; // вычитаниеol.get_xy {x, y) ;cout « " ( O l - o 2 ) X: " « x « ", Y: " « у « " \ n " ;ol = -ol; // отрицаниеol.get_xy (x, y) ;cout « " ( - o l ) X: " « x « ", Y: " « у « " \ n " ;return 0;Как видите, если минус перегружать как бинарный оператор, то у функциибудет один параметр. Если его перегружать как унарный оператор, то параметров не будет. Это отличие в числе параметров и делает возможным перегрузку минуса для обоих операторов. Как показано в программе, прииспользовании минуса в качестве бинарного оператора вызывается функцияoperator— (coord ob2), а в качестве унарного — функция operator— ()•УпраАнениения]1.
Перегрузите оператор — относительно класса coord. Создайте его префиксную и постфиксную формы.2. Перегрузите оператор + относительно класса coord так, чтобы он был какбинарным (как было показано ранее), так и унарным оператором. При использовании в качестве унарного оператор + должен делать положительнымзначение любой отрицательной координаты.6.5. Дружественные оператор-функцииКак отмечалось в начале этой главы, имеется возможность перегружать оператор относительно класса, используя не только функцию-член, но и дружественную функцию. Как вы знаете, дружественной функции указатель thisне передается.
В случае бинарного оператора это означает, что дружественной оператор-функции явно передаются оба операнда, а в случае унарного — один. Все остальное в обоих случаях одинаково, и нет особого смыславместо оператор-функции — члена класса использовать дружественную190Самоучитель C++оператор-функцию, за одним важным исключением, которое будет рассмотрено в примерах.Нельзя использовать дружественную функцию для перегрузки оператораприсваивания. Оператор присваивания можно перегружать только как оператор-функцию — член класса.1. Здесь функция operator+() перегружается для класса coord с использованиемдружественной функции:// Перегрузка оператора + относительно класса coord// с использованием дружественной функции#include <iostream>using namespace std;class coord {int x, у; // значения координатpublic:coord() { x = 0; y= 0; }coord (int i, int j) 1 x = i; у = j; }void get_xy(int si, int & j) { i = x; j = y; }friend coord operator*(coord obi, coord ob2););// Перегрузка оператора + с использованием дружественной функцииcoord operator+(coord obi, coord ob2){coord temp;temp.x = obl.x + ob2.x;temp.у = obi.у + ob2.y;return temp;int main(){coord ol(10, 10), o2(5, 3), o3;int x, y;o3 = ol + o2; // сложение двух объектов// вызов функции operator+{)Глава 6.
Введение в перегрузку операторов191o3.get_xy(х, у ) ;cout « "(ol + о2) X: " « х « ", Y: " « у « " \ п " ;return 0;Обратите внимание, что левый операнд передается первому параметру, аправый — второму.2. Перегрузка оператора посредством дружественной функции дает одну оченьважную возможность, которой нет у функции — члена класса. Используядружественную оператор-функцию, в операциях с объектами можно использовать встроенные типы данных, и при этом встроенный тип может располагаться слева от оператора. Как отмечалось ранее в этой главе, можноперегрузить оператор-функцию, являющуюся членом класса, так, что левыйоперанд становится объектом, а правый — значением встроенного типа.
Нонельзя для функции — члена класса располагать значение встроенного типаслева от оператора. Например, пусть перегружается оператор-функция член класса, тогда первая показанная здесь инструкция правильна, а втораянет:оЫ = оЬ2 + 10; // правильнооЫ = 10 + оЬ2; // неправильноНесмотря на то, что допустимо строить выражения так, как показано в первомпримере, необходимость постоянно думать о том, чтобы объект находился слеваот оператора, а значение встроенного типа — справа, может быть обременительной. Решение проблемы состоит в том, чтобы сделать перегруженную операторфункцию дружественной и задать обе возможные ситуации.Как вы знаете, дружественной оператор-функции передаются явно оба операнда. Таким образом, можно задать перегружаемую дружественную функцию так, чтобы левый операнд был объектом, а правый — операндом другоготипа.
Затем можно снова перегрузить оператор, чтобы левый операнд былзначением встроенного типа, а правый — объектом. Следующая программаиллюстрирует такой подход:// Дружественные оператор-функции придают гибкость программе^include <iostream>using namespace std;class coord {int х, у; // значения координатpublic:coord() { x = 0; y= 0; }coord(int i, int j) { x = i ; y = j ; }void get_xy(int Si, int &j) { i = x; j = y; }friend coord operator+(coord obi, int i);friend coord operator+(int i, coord obi);192Самоучитель C++II Перегрузка оператора + для операции, ob + intcoord operator-*-(coord obi, int i)coord temp;temp.x - obl.x + i;temp.
у = obi. у + i;return temp;}// Перегрузка оператора + для операции int •+• obcoord operator-Hint i, coord obi){coord temp;temp.x = obl.x + i;temp. у = obi. у + i;return temp;int main!){coord ol (10, 10) ;int x, y;ol = ol + 1 0 ; / / объект + целоеol .get_xy (x, y) ;cout « " ( o l + 10) X: " « x « ", Y: " « у « "\n";ol = 99 + ol; // целое + объектol.get_xy (x, y) ;cout « "(99 + ol) X: " « x « ", Y: " « у « "\n";return 0;В результате перегрузки дружественных оператор- функций становятся правильными обе инструкции:ol = ol +• 10;ol = 99 + ol;3.
При использовании дружественной оператор-функции для перегрузки унарного оператора ++ или — необходимо передавать операнд в функцию в качестве параметра- ссылки, поскольку дружественной функции не передаетсяуказатель this. Запомните, что в операторах инкремента и декремента подразумевается, что операнд будет изменен. Однако при перегрузке этих операторовпосредством дружественных функций операнд передается по значению. Такимобразом, любое изменение параметра внутри дружественной оператор-функции не влияет на объект, являющийся источником вызова. Поскольку при ис-Глава6.Введениевперегрузкуоператоров_/93пользовании дружественной функции отсутствует явно передаваемый указатель на объект (т. е.
указатель this), инкремент и декремент не влияют наоперанд.Однако при передаче операнда дружественной функции в качестве параметра-ссылки, изменения, которые имеют место внутри дружественной функции,влияют на объект, являющийся источником вызова. Например, в следующейпрограмме посредством дружественной функции перегружается оператор ++.// Перегрузка оператора ++ с использованием дружественной функции^include <iostrearn>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 Si, int &j) { i = x; j = y; }friend coord operator++ (coord &ob) ;// Перегрузка оператора ++ с использованием дружественной функцииcoord operator+-f (coord Sob) // использование ссылки// в качестве параметраob,x++;оЬ.у+-ь;return ob; // возвращение объекта,// ставшего источником вызоваint ma in ()coord ol(10, 10) ;int x, y;++ol; // объект ol передается по ссылкеol.get_xy (x, y) ;cout « "(++ol) X: " « x « ", У: " « у « "\n";return 0;Если вы используете современный компилятор, то с помощью дружественной оператор-функции можно определить разницу между префиксной ипостфиксной формами операторов инкремента и декремента точно так же,как это делалось с помощью функций-членов.
Просто добавьте целый параметр при задании постфиксной версии. Например, здесь приводятся пре-194Самоучитель C++фиксная и постфиксная версии оператора инкремента относительно классаcoord:•coord operator*-*- (coord Sob}; // префиксная версияcoord operator++(coord Sob, int notused); // постфиксная версияЕсли оператор +4- находится перед операндом, то вызывается функция coordoperatoH-+(coord &ob). Однако, если оператор ++ находится после операнда,вызывается функция coord operator++(coord &ob, int notused).
В этом случаепеременной notused будет передано значение 0.!УпраЖнения|leHUflj1. Перегрузите операторы — и / для класса coord посредством дружественныхфункций.2. Перепишите класс coord так, чтобы можно было использовать объекты типаcoord для умножения каждой из координат на целое.
Должны быть корректными обе следующие инструкции: ob * int и int * ob.3. Объясните, почему решение упражнения 2 требует использования дружественных оператор-функций.Покажите, как с помощью дружественной оператор-функции перегрузить оператор— относительно класса coord.
Определите как префиксную, так и постфиксную формы.6.6. Особенности использованияоператора присваиванияКак уже отмечалось, относительно класса можно перегрузить оператор присваивания. По умолчанию, если оператор присваивания применяется к объекту, то происходит поразрядное копирование объекта, стоящего справа отоператора, в объект, стоящий слева от оператора.