1629295407-c61bfe4caba98380ea3e7cdae6295416 (846200), страница 43
Текст из файла (страница 43)
Перегруженныйоператор “+” выполняет сложение отдельных координат двух ThreeD-объектов, аперегруженный оператор “-“ вычитает координаты одного ThreeD-объекта из координатдругого.// Пример перегрузки операторов.using System;// Класс трехмерных координат.class ThreeD {int x, y, z; // 3-х-мерные координаты.public ThreeD() {x = y = z = 0;}public ThreeD(int i, int j, int k) {x = i;y = j;z = k;}// Перегрузка бинарного оператора "+".public static ThreeD operator +(ThreeD op1,ThreeD op2){ThreeD result = new ThreeD();/* Суммирование координат двух точеки возврат результата. */result.x = op1.x + op2.x; // Эти операторы выполняютresult.y = op1.y + op2.y; // целочисленное сложение.result.z = op1.z + op2.z;return result;}// Перегрузка бинарного оператора "-".public static ThreeD operator -(ThreeD op1, ThreeD op2) {ThreeD result = new ThreeD();/* Обратите внимание на порядок операндов.op1 - левый операнд, op2 - правый.
*/result.x = op1.x - op2.x; // Эти операторы выполняютresult.y = op1.y - op2.y; // целочисленное вычитание.result.z = op1.z - op2.z;return result;}// Отображаем координаты X, Y, Z.226Часть I. Язык C#}public void show() {Console.WriteLine(x + ", " + y + ", " + z);}class ThreeDDemo {public static void Main() {ThreeD a = new ThreeD(1, 2, 3);ThreeD b = new ThreeD(10, 10, 10);ThreeD c = new ThreeD();Console.Write("Координаты точки a: ");a.show();Console.WriteLine();Console.Write("Координаты точки b: ");b.show();Console.WriteLine();c = a + b; // Складываем а и b.Console.Write("Результат сложения а + b: ");c.show();Console.WriteLine();c = a + b + c; // Складываем а, b и c.Console.Write("Результат сложения а + b + c: ");c.show();Console.WriteLine();c = c - a; // Вычитаем а из c.Console.Write("Результат вычитания c - a: ");c.show();Console.WriteLine();}}c = c - b; // Вычитаем b из c.Console.Write("Результат вычитания c - b: ");c.show();Console.WriteLine();При выполнении эта программа генерирует следующие результаты:Координаты точки a: 1, 2, 3Координаты точки b: 10, 10, 10Результат сложения а + b: 11, 12, 13Результат сложения а + b + c: 22, 24, 26Результат вычитания c - a: 21, 22, 23Результат вычитания c - b: 11, 12, 13Эту программу стоит рассмотреть подробнее.
Начнем с перегруженного оператора“+”. При воздействии оператора “+” на два объекта типа ThreeD величинысоответствующих координат суммируются, как показано в методе operator+(). Однакозаметьте, что этот метод не модифицирует значения ни одного из операндов. Этот методГлава 9. Перегрузка операторов227возвращает новый объект типа ThreeD, который содержит результат выполнениярассматриваемой операции. Это происходит и в случае стандартного арифметическогооператора сложения “+”, примененного, например, к числам 10 и 12. Результат операции10+12 равен 22, но при его получении ни 10, ни 12 не были изменены.
Хотя не существуетправила, которое бы не позволяло перегруженному оператору изменять значение одного изего операндов, все же лучше, чтобы он не противоречил общепринятым нормам.Обратите внимание на то, что метод operator+() возвращает объект типа ThreeD.Несмотря на то что он мог бы возвращать значение любого допустимого в C# типа, тотфакт, что он возвращает объект типа ThreeD, позволяет использовать оператор “+” в такихсоставных выражениях, как а + b + c. Здесь часть этого выражения, a+b, генерируетрезультат типа ThreeD, который затем суммируется с объектом с. И если бы выражениегенерировало значение иного типа (а не типа ThreeD), такое составное выражениепопросту не работало бы.И еще один важный момент.
При сложении координат внутри метода operator+()выполняется целочисленное сложение, поскольку отдельные координаты представляютсобой целочисленные величины. Факт перегрузки оператора “+” для объектов типа ThreeDне влияет на оператор “+”, применяемый к целым числам.Теперь рассмотрим операторный метод operator-(). Оператор "-" работаетподобно оператору “+” за исключением того, что здесь важен порядок следованияоперандов. Вспомните, что сложение коммутативно, а вычитание — нет (т.е.
А-В не то жесамое, что В-А). Для всех бинарных операторов первый параметр операторного методабудет содержать левый операнд, а второй параметр — правый. При реализацииперегруженных версий некоммутативных операторов необходимо помнить, какой операндявляется левым, а какой — правым.Перегрузка унарных операторовУнарные операторы перегружаются точно так же, как и бинарные.
Главное отличие,конечно же, состоит в том, что в этом случае существует только один операнд. Рассмотрим,например, метод, который перегружает унарный “минус” для класса ThreeD.// Перегрузка унарного оператора "-".public static ThreeD operator -(ThreeD op) {ThreeD result = new ThreeD();result.x = -op.x;result.y = -op.y;result.z = -op.z;}return result;Здесь создается новый объект, который содержит поля операнда, но со знаком“минус”. Созданный таким образом объект и возвращается операторным методомoperator-().Обратитевниманиенато,чтосамоперандостаетсянемодифицированным.
Такое поведение соответствует обычному действию унарного“минуса”. Например, в выраженииа = -bа получает значение b, взятое с противоположным знаком, но само b при этом не меняется.228Часть I. Язык C#Однако в двух случаях операторный метод изменяет содержимое операнда. Речь идетоб операторах инкремента (++) и декремента (--). Поскольку обычно (“в миру”) этиоператоры выполняют функции инкрементирования и декрементирования значений,соответственно, то перегруженные операторы “+” и “-“, как правило, инкрементируют свойоперанд. Таким образом, при перегрузке этих операторов операнд обычно модифицируется.Например, рассмотрим метод operator++-() для класса ThreeD.// Перегрузка унарного оператора "++".public static ThreeD operator ++(ThreeD op){// Оператор "++" модифицирует аргумент.op.x++;op.y++;op.z++;return op;}Обратите внимание: в результате выполнения этого операторного метода объект, накоторый ссылается операнд ор, модифицируется.
Итак, операнд, подвергнутый операции“++”, инкрементируется. Более того, модифицированный объект возвращается этимметодом, благодаря чему оператор “++” можно использовать в более сложных выражениях.Ниже приведена расширенная версия предыдущего примера программы, которая,помимо прочего, демонстрирует определение и использование унарных операторов “-“ и“++”.// Перегрузка большего числа операторов.using System;// Класс трехмерных координат.class ThreeD {int x, y, z; // 3-х-мерные координаты.public ThreeD() {x = y = z = 0;}public ThreeD(int i, int j, int k) {x = i;y = j;z = k;}// Перегрузка бинарного оператора "+".public static ThreeD operator +(ThreeD op1, ThreeD op2){ThreeD result = new ThreeD();/* Суммирование координат двух точеки возврат результата.
*/result.x = op1.x + op2.x;result.y = op1.y + op2.y;result.z = op1.z + op2.z;return result;}// Перегрузка бинарного оператора "-".public static ThreeD operator -(ThreeD op1, ThreeD op2){ThreeD result = new ThreeD();/* Обратите внимание на порядок операндов.Глава 9. Перегрузка операторов229}op1 - левый операнд, op2 - правый. */result.x = op1.x - op2.x;result.y = op1.y - op2.y;result.z = op1.z - op2.z;return result;// Перегрузка унарного оператора "-".public static ThreeD operator -(ThreeD op) {ThreeD result = new ThreeD();result.x = -op.x;result.y = -op.y;result.z = -op.z;return result;}// Перегрузка унарного оператора "++".public static ThreeD operator ++(ThreeD op) {// Оператор "++" модифицирует аргумент.op.x++;op.y++;op.z++;return op;}// Отображаем координаты X, Y, Z.public void show(){Console.WriteLine(x + ", " + y + ", " + z);}}class ThreeDDemo {public static void Main() {ThreeD a = new ThreeD(1, 2, 3);ThreeD b = new ThreeD(10, 10, 10);ThreeD c = new ThreeD();Console.Write("Координаты точки a: ");a.show();Console.WriteLine();Console.Write("Координаты точки b: ");b.show();Console.WriteLine();c = a + b; // Сложение а и b.Console.Write("Результат сложения а + b: ");c.show();Console.WriteLine();c = a + b + c; // Сложение a, b и c.Console.Write("Результат сложения а + b + c: ");230Часть I.
Язык C#c.show();Console.WriteLine();c = c - a; // Вычитание а из c.Console.Write("Результат вычитания c - a: ");c.show();Console.WriteLine();c = c - b; // Вычитание b из c.Console.Write("Результат вычитания c - b: ");c.show();Console.WriteLine();c = -a; // Присваивание -а объекту c.Console.Write("Результат присваивания -a: ");c.show();Console.WriteLine();}}a++; // Инкрементирование а.Console.Write("Результат инкрементирования a++: ");a.show();Результаты выполнения этой программы выглядят так:Координаты точки a: 1, 2, 3Координаты точки b: 10, 10, 10Результат сложения а + b: 11, 12, 13Результат сложения а + b + c: 22, 24, 26Результат вычитания c - a: 21, 22, 23Результат вычитания c - b: 11, 12, 13Результат присваивания -a: -1, -2, -3Результат инкрементирования a++: 2, 3, 4Как вы уже знаете, операторы “++” и “—“ имеют как префиксную, так и постфикснуюформу. Например, инструкции++а;иa++;представляют собой допустимое использование оператора инкремента.
Однако приперегрузке оператора “++” обе формы вызывают один и тот же метод. Следовательно, вэтом случае невозможно отличить префиксную форму оператора “++” от постфиксной. Этокасается и перегрузки оператора “—“.Глава 9. Перегрузка операторов231Выполнение операций над значениямивстроенных C#-типовДля любого заданного класса и оператора любой операторный метод сам можетперегружаться. Одна из самых распространенных причин этого — разрешить операциимежду объектами этого класса и другими (встроенными) типами данных. В качествепримера давайте снова возьмем класс ThreeD.
Вы видели, как перегрузить оператор “+”,чтобы он суммировал координаты одного ThreeD-объекта с координатами другого.Однако это не единственный способ определения операции сложения для класса ThreeD.Например, может потребоваться суммирование какого-либо целого числа с каждойкоординатой ThreeD-объекта. Ведь тогда эту операцию можно использовать для смещенияосей. Для ее реализации необходимо перегрузить оператор “+” еще раз, например, так:// Перегружаем бинарный оператор "+" для суммирования// объекта и int-значения.public static ThreeD operator +(ThreeD op1, int op2){ThreeD result = new ThreeD();}result.x = op1.x + op2;result.y = op1.y + op2;result.z = op1.z + op2;return result;Обратите внимание на то, что второй параметр имеет тип int.
Таким образом, этотметод позволяет сложить int-значение с каждым полем ThreeD-объекта. Это вполнедопустимо, поскольку, как разъяснялось выше, при перегрузке бинарного оператора типтолько одного из его операндов должен совпадать с типом класса, для которогоперегружается этот оператор. Другой операнд может иметь любой тип.Ниже приведена версия класса ThreeD, которая имеет два перегруженных методаoperator+()./* Перегрузка оператора сложения для вариантов:объект + объект и объект + int-значение. */using System;// Класс трехмерных координат.class ThreeD {int x, y, z; // 3-х-мерные координаты.public ThreeD() {x = y = z = 0;}public ThreeD(int i, int j, int k) {x = i;y = j;z = k;}// Перегружаем бинарный оператор "+" для варианта// "объект + объект".public static ThreeD operator +(ThreeD op1, ThreeD op2){ThreeD result = new ThreeD();/* Суммирование координат двух точеки возврат результата.