Г. Шилтд - Самоучитель C++ (PDF) (1114887), страница 27
Текст из файла (страница 27)
Например, в приведенном ниже примере оператор + перегружается так, что прибавляет целое значение к объекту типа coord:// Перегрузка оператора + как для операции ob-fob,// так и для операции ob+int#include <iostream>using namespace std;class coord {int x, у; // значения координатpublic:coord0 { x = 0; у = 0; }coord (int i, int j) { x = i; у = j; }void get_xy(int fii, int &j) { i = x; j = y; }coord operator+(coord ob2); // ob + obcoord operator+(int i); // ob + int// Перегрузка оператора + относительно класса coordcoord coord::operators(coord ob2){coord temp;temp.x = x +ob2.x;temp.у = у +оЬ2.у;return temp;Глава 6.
Введение в перегрузку операторов183II Перегрузка оператора + для операции ob-t-intcoord coord::operator+(int i){coord temp;temp.x = x + i;temp.у = у + i;return temp;int main()coord ol (10, 10), o2(5, 3), o3;int x, y;o3 = ol + o2; // сложение двух объектов// вызов функции operator+ (coord)o3.get_xy (x, у) ;cout « "(ol + o2) X: " « x « ", Y: " « у « "\n";o3 = ol + 100; // сложение объекта и целого// вызов функции operator+(int)o3.get_xy (x, y};cout « "(ol + 100) X: " « x « ", Y: " « у « "\n";return 0;Здесь важно запомнить следующее: когда оператор-функция — член классаперегружается так, чтобы объект этого класса можно было использовать водной операции с переменной встроенного типа данных, встроенный типданных должен находиться справа от оператора.
Смысл этого легко понять:он в том, что объект, который находится слева, генерирует вызов операторфункции. Однако что произойдет, если компилятор встретит следующую инструкцию?оЗ = 19 + ol; // int + obДля обработки сложения целого с объектом встроенной операции не существует. Перегруженная функция operator+(int i) работает только в том случае,если объект находится слева от оператора. Поэтому эта инструкция приведет кошибке при компиляции.
(Позже вы узнаете способ обойти это ограничение.)4. В оператор -функции можно использовать параметр -ссылку. Например, допустимым способом перегрузки оператора + относительно класса coord является следующий:// Перегрузка + относительно класса coord, с использованием ссылкиcoord coord: :operator-t-(coord &ob2)184Самоучитель C++coord temp;temp.x = x + ob2.x;temp. у = у + ob2.y;ьreturn temp;Одним из доводов в пользу использования ссылки в качестве параметра оператор-функции является ее эффективность.
Передача объекта функции в качестве параметра часто требует больших затрат процессорного времени.Передача же адреса объекта всегда быстрее и эффективней. Если оператормногократно используется, параметр-ссылка обычно позволяет значительноповысить производительность.Другой довод в пользу использования параметра-ссылки состоит в том, чтоссылка позволяет избежать неприятностей, связанных с удалением копииоперанда.
Как вы знаете по предыдущим главам, при передаче аргумента позначению создается его копия, Если у такого объекта есть деструктор, то после завершения выполнения функции вызывается деструктор копии. Иногдавозможны ситуации, когда деструктор удаляет нечто такое, что необходимовызывающему объекту. Использование в этом случае в качестве параметра несамого объекта, а ссылки на этот объект — это простой (и эффективный)способ избежать проблем. Тем не менее, запомните, что в общем случае решить эту проблему могло бы определение конструктора копий.Упражненияения]1.
Для класса coord перегрузите операторы * и /. Продемонстрируйте их работу.2. В приведенном ниже примере некорректно перегружен оператор %. Почему?coord coord::operator%(coord ob){double i;cout « "Введите число: ";cin » i;i3cout « "корень " « i « " равен ";cout « sqr(i);Поэкспериментируйте, меняя тип возвращаемого значения оператор-функций на что-нибудь отличное от coord. Обратите внимание на генерируемыекомпилятором сообщения об ошибках.Глава 6. Введение в перегрузку операторов1856.3. Перегрузка операторов отношенияи логических операторовСуществует возможность перегрузки операторов отношения и логическихоператоров. При перегрузке операторов отношения и логических операторовтак, чтобы они вели себя обычным образом, не нужны оператор-функции,возвращающие объект класса, для которого эти оператор-функции определены. Вместо этого они должны возвращать целое, интерпретируемое какзначение true или false.
Помимо того, что возвращаемым значением такихоператор-функций должно быть значение true или false, должна быть возможность встраивания операторов отношения и логических операторов вбольшие выражения, включающие также данные других типов.^Замечаниеi/'8 современных компиляторах C++ оператор-функции для перегрузки операторов отношения и логических операторов могут возвращать значения булева типа, хотя особого преимущества в этом нет. Как было описано в главе 1,в булевом типе данных определены только два значения — true и false. Этизначения автоматически конвертируются в ненулевое и нулевое значения.
Инаоборот, целые ненулевое и нулевое значения автоматически конвертируются в значения true и false.Примеры• -х1. В следующей программе перегружаются операторы == и &&:II Перегрузка операторов == и && относительно класса 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; }int operator^ (coord ob2);int operators &(coord ob2);// Перегрузка оператора == для класса coordint coord::operator==(coord ob2){return x==ob2.x && y==ob2.y;186Самоучитель C++// Перегрузка оператора && для класса coordint coord::operators&(coord ob2){return (x && ob2.x) && (у && ob2.y);\int main()tcoord ol(10, 10), o2{5, 3}, o3(10, 10), o4 (0, 0);if(ol==o2) cout « "ol равно o2\n";else cout « "ol не равно o2\n";if(ol==o3) cout « "ol равно o3\n";else cout « "ol не равно оЗ\п";if(ol&&o2) cout « "ol && o2 равно истина\п";else cout « "ol && o2 равно ложь\п";if(ol£&o4) cout « "ol && o4 равно истина\п";else cout « "ol 5& o4 равно ложь\п";return 0;1.
Относительно класса coord перегрузите операторы отношения < и >.6.4. Перегрузка унарных операторовПерегрузка унарных операторов аналогична перегрузке бинарных, за исключением того, что мы имеем дело не с двумя, а с одним операндом. При перегрузке унарного оператора с использованием функции-члена у функциинет параметров. Поскольку имеется только один операнд, он и генерируетвызов оператор-функции.
Другие параметры не нужны.' ПримерыР1. В следующей программе относительно класса coord перегружается операторинкремента (++):// Перегрузка оператора ++ относительно класса coord^include <iostream>using namespace std;Глава6.Введениевперегрузкуоператоров_767class coord {int x, у; // значения координатpublic:coord () { х = 0; у = 0; }coord (int i, int j) { x = i; у = j; }void get_xy(int Si, int Sj) { i = x; j = y; }coord operator-n- () ;};// Перегрузка оператора ++ для класса coordcoord coord: :operator++ ()return *this;int main { }coord o l U O , 10) ;int x, y;-м-ol; // инкремент объектаol.get_xy(x, у ) ;cout « "(++ol) X: " « x « ", Y: " « у « "\n";return 0;Поскольку оператор инкремента увеличивает свой операнд на единицу, перегрузка этого оператора меняет объект, с которым он работает.
Это позволяет использовать оператор инкремента в качестве части более сложнойинструкции, например, такой:о2 = ++ol;Как и в случае бинарных операторов, нет правила, которое заставляло быперегружать унарный оператор с сохранением его обычного смысла. Однаков большинстве случаев лучше поступать именно так.2. В ранних версиях C++ при перегрузке оператора инкремента или декрементаположения операторов ++ и — относительно операнда не различались. Поэтому по отношению к предыдущей программе следующие две инструкцииэквивалентны:-H-ol;Однако в современной спецификации C++ определен способ, по которомукомпилятор может различить эти две инструкции. В соответствии с этим188_•_СамоучительC++способом задаются две версии функции operator++().
Первая определяетсятак, как было показано в предыдущем примере. Вторая определяется следующим образом:coord coord: :operator++ (int notused);Если оператор ++ указан перед операндом, вызывается функцияoperator++(). Если оператор ++ указан после операнда, вызывается функцияopera tor++ (int notused). В этом случае переменной notused передается значение 0. Таким образом, если префиксный и постфиксный инкремент или декремент важны для объектов вашего класса, то понадобится реализовать обеоператор - функции.3.