Текст книги "Полное руководство. С# 4.0"
Автор книги: Герберт Шилдт
Жанр:
Программирование
сообщить о нарушении
Текущая страница: 17 (всего у книги 58 страниц)
Координаты точки а: 1, 2, 3 Координаты точки b: 10, 10, 10 Результат сложения а + b: 11, 12, 13 Результат сложения а + b + с: 22, 24, 26 Результат вычитания с – а: 21, 22, 23 Результат вычитания с – b: 11, 12, 13 Результат присваивания -а: -1, -2, -3 Если с = а++ то координаты точки с равны 1, 2, 3 а координаты точки а равны 2, 3, 4 Установка исходных координат точки а: 1, 2, 3 Если с = ++а то координаты точки с равны 2, 3, 4 а координаты точки а равны 2, 3, 4 ## Выполнение операций со встроенными в C# типами данных Для любого заданного класса и оператора имеется также возможность перегрузить сам операторный метод. Это, в частности, требуется для того, чтобы разрешить опера ции с типом класса и другими типами данных, в том числе и встроенными. Вновь об ратимся к классу ThreeD. На примере этого класса ранее было показано, как оператор + перегружается для сложения координат одного объекта типа ThreeD с координата ми другого. Но это далеко не единственный способ определения операции сложения для класса ThreeD. Так, было бы не менее полезно прибавить целое значение к каждой координате объекта типа ThreeD. Подобная операция пригодилась бы для переноса осей координат. Но для ее выполнения придется перегрузить оператор + еще раз, как показано ниже.
// Перегрузить бинарный оператор + для сложения объекта // типа ThreeD и целого значения типа int. public static ThreeD operator +(ThreeD op1, int op2) { ThreeD result = new ThreeD(); result.x = op1.x + op2; result.у = op1.y + op2; result.z = op1.z + op2; return result; } Как видите, второй параметр операторного метода имеет тип int. Следовательно, в этом методе разрешается сложение целого значения с каждым полем объекта типа ThreeD. Такая операция вполне допустима, потому что, как пояснялось выше, при перегрузке бинарного оператора один из его операндов должен быть того же типа, что и класс, для которого этот оператор перегружается. Но у второго операнда этого оператора может быть любой другой тип. Ниже приведен вариант класса ThreeD с двумя перегружаемыми методами опе ратора +.
// Перегрузить бинарный оператор + дважды: // один раз – для сложения объектов класса ThreeD, // а другой раз – для сложения объекта типа ThreeD и целого значения типа int. using System;
// Класс для хранения трехмерных координат. class ThreeD { int х, у, z; // трехмерные координаты public ThreeD() { x = у = z = 0; } public ThreeD(int i, int j, int k) { x = i; у = j; z = k; } // Перегрузить бинарный оператор + для сложения объектов класса ThreeD. public static ThreeD operator + (ThreeD op1, ThreeD op2) { ThreeD result = new ThreeD(); / Сложить координаты двух точек и возвратить результат. / result.х = op1.x + ор2.х; result.у = op1.у + ор2.у; result.z = op1.z + op2.z; return result; } // Перегрузить бинарный оператор + для сложения // объекта типа ThreeD и целого значения типа int. public static ThreeD operator +(ThreeD opl, int op2) { ThreeD result = new ThreeD(); result.x = op1.x + op2; result.у = op1.у + op2; result.z = op1.z + op2; return result; } // Вывести координаты X, Y, Z. public void Show() { Console.WriteLine(x + ", " + у + ", " + z); } }
class ThreeDDemo { static void Main() { ThreeD a = new ThreeD(1, 2, 3); ThreeD b = new ThreeD(10, 10, 10); ThreeD с = new ThreeD(); Console.Write("Координаты точки a; "); a.Show(); Console.WriteLine(); Console.Write("Координаты точки b: "); b.Show(); Console.WriteLine(); с = a + b; // сложить объекты класса ThreeD Console.Write("Результат сложения a + b: "); c.Show(); Console.WriteLine(); c = b + 10; // сложить объект типа ThreeD и целое значение типа int Console.Write("Результат сложения b + 10: "); с.Show(); }
} При выполнении этого кода получается следующий результат.
Координаты точки а: 1, 2, 3 Координаты точки b: 10, 10, 10 Результат сложения а + b: 11, 12, 13 Результат сложения b + 10: 20, 20, 20 Как подтверждает приведенный выше результат, когда оператор + применяется к двум объектам класса ThreeD, то складываются их координаты. А когда он применяет ся к объекту типа ThreeD и целому значению, то координаты этого объекта увеличи ваются на заданное целое значение. Продемонстрированная выше перегрузка оператора +, безусловно, расширяет по лезные функции класса ThreeD, тем не менее, она делает это не до конца. И вот по чему. Метод operator+(ThreeD, int) позволяет выполнять операции, подобные следующей.
ob1 = оb2 + 10; Но, к сожалению, он не позволяет выполнять операции, аналогичные следующей.
ob1 = 10 + оb2; Дело в том, что второй целочисленный аргумент данного метода обозначает правый операнд бинарного оператора +, но в приведенной выше строке кода целочисленный аргумент указывается слева. Для того чтобы разрешить выполнение такой операции сложения, придется перегрузить оператор + еще раз. В этом случае первый параметр операторного метода должен иметь тип int, а второй параметр – тип ThreeD. Таким образом, в одном варианте метода operator+() выполняется сложение объекта типа ThreeD и целого значения, а во втором – сложение целого значения и объекта типа ThreeD. Благодаря такой перегрузке оператора + (или любого другого бинарного опе ратора) допускается появление встроенного типа данных как с левой, так и с правой стороны данного оператора. Ниже приведен еще один вариант класса ThreeD, в кото ром бинарный оператор + перегружается описанным выше образом.
// Перегрузить бинарный оператор + трижды: // один раз – для сложения объектов класса ThreeD, // второй раз – для сложения объекта типа ThreeD и целого значения типа int, // а третий раз – для сложения целого значения типа int и объекта типа ThreeD. using System;
// Класс для хранения трехмерных координат. class ThreeD { int х, у, z; // трехмерные координаты public ThreeD() { x = y = z = 0; } public ThreeD(int i, int j, int k) { x = i; у = j; z = k; } // Перегрузить бинарный оператор + для сложения объектов класса ThreeD. public static ThreeD operator +(ThreeD op1, ThreeD op2) { ThreeD result = new ThreeD(); / Сложить координаты двух точек и возвратить результат. / result.х = op1.x + ор2.х; result.у = op1.y + ор2.у; result.z = op1.z + op2.z; return result; } // Перегрузить бинарный оператор + для сложения // объекта типа ThreeD и целого значения типа int. public static ThreeD operator +(ThreeD op1, int op2) { ThreeD result = new ThreeD(); result.x = op1.x + op2; result.у = op1.y + op2; result.z = op1.z + op2; return result; } // Перегрузить бинарный оператор + для сложения // целого значения типа int и объекта типа ThreeD. public static ThreeD operator +(int op1, ThreeD op2) { ThreeD result = new ThreeD(); result.x = op2.x + op1; result.у = op2.y + op1; result.z = op2.z + op1; return result; } // Вывести координаты X, Y, Z. public void Show() { Console.WriteLine(x + ", " + у + ", " + z); } }
class ThreeDDemo { static void Main() { ThreeD a = new ThreeD(l, 2, 3); ThreeD b = new ThreeD(10, 10, 10); ThreeD с = new ThreeD(); Console.Write("Координаты точки a: "); a.Show(); Console.WriteLine(); Console.Write("Координаты точки b: "); b.Show(); Console.WriteLine(); с = a + b; // сложить объекты класса ThreeD Console.Write("Результат сложения a + b: "); c.Show(); Console.WriteLine(); c = b + 10; // сложить объект типа ThreeD и целое значение типа int Console.Write("Результат сложения b + 10: "); с.Show(); Console.WriteLine(); с = 15 + b; // сложить целое значение типа int и объект типа ThreeD Console.Write("Результат сложения 15 + b: "); с.Show(); }
} Выполнение этого кода дает следующий результат.
Координаты точки а: 1, 2, 3 Координаты точки b: 10, 10, 10 Результат сложения а + b: 11, 12, 13 Результат сложения b + 10: 20, 20, 20 Результат сложения 15 + b: 25, 25, 25 ### Перегрузка операторов отношения Операторы отношения, например == и <, могут также перегружаться, причем очень просто. Как правило, перегруженный оператор отношения возвращает ло гическое значение true и false. Это вполне соответствует правилам обычного применения подобных операторов и дает возможность использовать их перегру жаемые разновидности в условных выражениях. Если же возвращается результат другого типа, то тем самым сильно ограничивается применимость операторов от ношения. Ниже приведен очередной вариант класса ThreeD, в котором перегружаются операторы < и >. В данном примере эти операторы служат для сравнения объектов ThreeD, исходя из их расстояния до начала координат. Один объект считается больше другого, если он находится дальше от начала координат. А кроме того, один объект считается меньше другого, если он находится ближе к началу координат. Такой вари ант реализации позволяет, в частности, определить, какая из двух заданных точек на ходится на большей сфере. Если же ни один из операторов не возвращает логическое значение true, то обе точки находятся на одной и той же сфере. Разумеется, возможны и другие алгоритмы упорядочения.
// Перегрузить операторы < и >. using System;
// Класс для хранения трехмерных координат. class ThreeD { int х, у, z; // трехмерные координаты public ThreeD() { х = у = z = 0; } public ThreeD(int i, int j, int k) { x = i; у = j; z = k; } // Перегрузить оператор <. public static bool operator <(ThreeD op1, ThreeD op2) { if(Math.Sqrt(op1.x op1.x + op1.y op1.y + op1.z op1.z) < Math.Sqrt(op2.x op2.x + op2.у op2.y + op2.z op2.z)) return true; else return false; } // Перегрузить оператор >. public static bool operator >(ThreeD op1, ThreeD op2) { if(Math.Sqrt(op1.x op1.x + op1.y op1.y + op1.z op1.z) > Math.Sqrt(op2.x op2.x + op2.у op2.у + op2.z op2.z)) return true; else return false; } // Вывести координаты X, Y, Z. public void Show() { Console.WriteLine(x + ", " + у + ", " + z); } }
class ThreeDDemo { static void Main() { ThreeD a = new ThreeD(5, 6, 7); ThreeD b = new ThreeD(10, 10, 10); ThreeD с = new ThreeD(1, 2, 3); ThreeD d = new ThreeD(6, 7, 5); Console.Write("Координаты точки a: "); a.Show(); Console.Write("Координаты точки b: "); b.Show(); Console.Write("Координаты точки с: "); c.Show(); Console.Write("Координаты точки d: "); d.Show(); Console.WriteLine(); if(а > с) Console.WriteLine("а > с истинно"); if(а < с) Console.WriteLine("а < с истинно"); if(а > b) Console.WriteLine("а > b истинно"); if(а < b) Console.WriteLine("а < b истинно"); if(а > d) Console.WriteLine("а > d истинно"); else if(а < d) Console.WriteLine("a < d истинно"); else Console.WriteLine("Точки a и d находятся на одном расстоянии " + "от начала отсчета"); }
} Вот к какому результату приводит выполнение этого кода.
Координаты точки а: 5, 6, 7 Координаты точки b: 10, 10, 10 Координаты точки с: 1, 2, 3 Координаты точки d: 6, 7, 5 а > с истинно а < b истинно Точки a и d находятся на одном расстоянии от начала отсчета На перегрузку операторов отношения накладывается следующее важное ограни чение: они должны перегружаться попарно. Так, если перегружается оператор <, то следует перегрузить и оператор >, и наоборот. Ниже приведены составленные в пары перегружаемые операторы отношения. == != < > <= >=
И еще одно замечание: если перегружаются операторы == и !=, то для это го обычно требуется также переопределить методы Object.Equals() и Object. GetHashCode(). Эти методы и способы их переопределения подробнее рассматри ваются в главе 11. Перегрузка операторов true и false
Ключевые слова true и false можно также использовать в качестве унарных опе раторов для целей перегрузки. Перегружаемые варианты этих операторов позволяют определить назначение ключевых слов true и false специально для создаваемых клас сов. После перегрузки этих ключевых слов в качестве унарных операторов для конкрет ного класса появляется возможность использовать объекты этого класса для управления операторами if, while, for и do-while или же в условном выражении ?.
Операторы true и false должны перегружаться попарно, а не раздельно. Ниже приведена общая форма перегрузки этих унарных операторов. public static bool operator true(тип_параметра операнд) { // Возврат логического значения true или false. } public static bool operator false(тип_параметра операнд) { // Возврат логического значения true или false. }
Обратите внимание на то, что и в том и в другом случае возвращается результат типа bool.
Ниже приведен пример программы, демонстрирующий реализацию операторов true и false в классе ThreeD. В каждом из этих операторов проверяется следующее условие: если хотя бы одна из координат объекта типа ThreeD равна нулю, то этот объект истинен, а если все три его координаты равны нулю, то такой объект ложен. В данном примере программы реализован также оператор декремента исключительно в целях демонстрации. // Перегрузить операторы true и false для класса ThreeD. using System; // Класс для хранения трехмерных координат. class ThreeD { int х, у, z; // трехмерные координаты public ThreeD() { х = у = z = 0; } public ThreeD(int i, int j, int k) { x = i; у = j; z = k; } // Перегрузить оператор true. public static bool operator true(ThreeD op) { if((op.x != 0) || (op.у != 0) || (op.z != 0)) return true; // хотя бы одна координата не равна нулю else return false; } // Перегрузить оператор false. public static bool operator false(ThreeD op) { if((op.x == 0) && (op.у == 0) && (op.z == 0)) return true; // все координаты равны нулю else return false; } // Перегрузить унарный оператор –. public static ThreeD operator –(ThreeD op) { ThreeD result = new ThreeD(); // Возвратить результат декрементирования. result.x = op.x – 1; result.у = op.у – 1; result.z = op.z – 1; return result; } // Вывести координаты X, Y, Z. public void Show() { Console.WriteLine(x + ", " + у + ", " + z); } } class TrueFalseDemo { static void Main() { ThreeD a = new ThreeD(5, 6, 7); ThreeD b = new ThreeD(10, 10, 10); ThreeD с = new ThreeD (0, 0, 0); Console.Write("Координаты точки a: "); a.Show(); Console.Write("Координаты точки b: "); b.Show(); Console.Write("Координаты точки с: "); c.Show(); Console.WriteLine(); if(a) Console.WriteLine("Точка а истинна."); else Console.WriteLine("Точка а ложна."); if(b) Console.WriteLine("Точка b истинна."); else Console.WriteLine("Точка b ложна."); if(с) Console.WriteLine("Точка с истинна."); else Console.WriteLine("Точка с ложна."); Console.WriteLine(); Console.WriteLine("Управление циклом с помощью объекта класса ThreeD."); do { b.Show(); b–; } while(b); } }
Выполнение этой программы приводит к следующему результату. Координаты точки а: 5, 6, 7 Координаты точки b: 10, 10, 10 Координаты точки с: 0, 0, 0 Точка а истинна Точка b истинна Точка с ложна Управление циклом с помощью объекта класса ThreeD. 10, 10, 10 9, 9, 9 8, 8, 8 7, 7, 7 6, 6, 6 5, 5, 5 4, 4, 4 3, 3, 3 2, 2, 2 1, 1, 1
Обратите внимание на то, как объекты класса ThreeD используются для управле ния условным оператором if и оператором цикла do-while. Так, в операторах if объект типа ThreeD проверяется с помощью оператора true. Если результат этой проверки оказывается истинным, то оператор if выполняется. А в операторе цикла do-while объект b декрементируется на каждом шаге цикла. Следовательно, цикл повторяется до тех пор, пока проверка объекта b дает истинный результат, т.е. этот объект содержит хотя бы одну ненулевую координату. Если же окажется, что объект b содержит все нулевые координаты, его проверка с помощью оператора true даст ложный результат и цикл завершится. Перегрузка логических операторов
Как вам должно быть уже известно, в C# предусмотрены следующие логические операторы: &, |, !, && и ||. Из них перегрузке, безусловно, подлежат только опера торы &, | и !. Тем не менее, соблюдая определенные правила, можно извлечь также пользу из укороченных логических операторов && и ||. Все эти возможности рассма триваются ниже. Простой способ перегрузки логических операторов
Рассмотрим сначала простейший случай. Если не пользоваться укороченными ло гическими операторами, то перегрузку операторов & и | можно выполнять совершен но естественным путем, получая в каждом случае результат типа bool. Аналогичный результат, как правило, дает и перегружаемый оператор !.
Ниже приведен пример программы, в которой демонстрируется перегрузка логи ческих операторов !, & и | для объектов типа ThreeD. Как и в предыдущем примере, объект типа ThreeD считается истинным, если хотя бы одна из его координат не равна нулю. Если же все три координаты объекта равны нулю, то он считается ложным. // Простой способ перегрузки логических операторов // !, | и & для объектов класса ThreeD. using System; // Класс для хранения трехмерных координат. class ThreeD { int х, у, z; // трехмерные координаты public ThreeD() { х = у = z = 0; } public ThreeD(int i, int j, int k) { x = i; у = j; z = k; } // Перегрузить логический оператор |. public static bool operator |(ThreeD op1, ThreeD op2) { if( ((op1.x != 0) || (op1.у != 0) || (op1.z != 0)) | ((op2.x != 0) || (op2.у != 0) || (op2.z != 0)) ) return true; else return false; } // Перегрузить логический оператор &. public static bool operator &(ThreeD op1, ThreeD op2) { if( ((op1.x != 0) && (op1.у != 0) && (op1.z != 0)) & ((op2.x != 0) && (op2.y != 0) && (op2.z != 0)) ) return true; else return false; } // Перегрузить логический оператор !. public static bool operator !(ThreeD op) { if((op.x != 0) || (op.y != 0) || (op.z != 0)) return false; else return true; } // Вывести координаты X, Y, Z. public void Show() { Console.WriteLine(x + ", " + у + ", " + z); } } class TrueFalseDemo { static void Main() { ThreeD a = new ThreeD(5, 6, 7); ThreeD b = new ThreeD(10, 10, 10); ThreeD с = new ThreeD(0, 0, 0); Console.Write("Координаты точки a: "); a.Show(); Console.Write("Координаты точки b: "); b.Show(); Console.Write("Координаты точки с: "); c.Show(); Console.WriteLine(); if(!a) Console.WriteLine("Точка а ложна."); if(!b) Console.WriteLine("Точка b ложна."); if(!c) Console.WriteLine("Точка с ложна."); Console.WriteLine(); if(a & b) Console.WriteLine("a & b истинно."); else Console.WriteLine("a & b ложно."); if(a & c) Console.WriteLine("a & с истинно."); else Console.WriteLine("a & с ложно."); if(a | b) Console.WriteLine("a | b истинно."); else Console.WriteLine("a | b ложно."); if(a | c) Console.WriteLine("a | с истинно."); else Console.WriteLine("a | с ложно."); } }
При выполнении этой программы получается следующий результат. Координаты точки а: 5, 6, 7 Координаты точки b: 10, 10, 10 Координаты точки с: 0, 0, 0 Точка с ложна. а & b истинно. a & с ложно. а | b истинно. а | с истинно.
При таком способе перегрузки логических операторов &, | и ! методы каждого из них возвращают результат типа bool. Это необходимо для того, чтобы использовать рассматриваемые операторы обычным образом, т.е. в тех выражениях, где предпола гается результат типа bool. Напомним, что для всех встроенных в C# типов данных результатом логической операции должно быть значение типа bool. Поэтому впол не разумно предусмотреть возврат значения типа bool и в перегружаемых вариан тах этих логических операторов. Но, к сожалению, такой способ перегрузки пригоден лишь в том случае, если не требуются укороченные логические операторы. Как сделать укороченные логические операторы доступными для применения
Для того чтобы применение укороченных логических операторов && и || стало возможным, необходимо соблюсти следующие четыре правила. Во-первых, в классе должна быть произведена перегрузка логических операторов & и |. Во-вторых, пере гружаемые методы операторов & и | должны возвращать значение того же типа, что и у класса, для которого эти операторы перегружаются. В-третьих, каждый параметр должен содержать ссылку на объект того класса, для которого перегружается логиче ский оператор. И в-четвертых, для класса должны быть перегружены операторы true и false. Если все эти условия выполняются, то укороченные логические операторы автоматически становятся пригодными для применения.
В приведенном ниже примере программы показано, как правильно реализовать логические операторы & и | в классе ThreeD, чтобы сделать доступными для примене ния укороченные логические операторы && и ||. /* Более совершенный способ перегрузки логических операторов !, | и & для объектов класса ThreeD. В этом варианте укороченные логические операторы && и || становятся доступными для применения автоматически. */ using System; // Класс для хранения трехмерных координат. class ThreeD { int х, у, z; // трехмерные координаты public ThreeD() { х = у = z = 0; } public ThreeD(int i, int j, int k) { x = i; у = j; z = k; } // Перегрузить логический оператор | для укороченного вычисления. public static ThreeD operator |(ThreeD op1, ThreeD op2) { if( ((op1.x != 0) || (op1.y != 0) || (op1.z != 0)) | ((op2.x != 0) || (op2.у != 0) || (op2.z != 0)) ) return new ThreeD(1, 1, 1); else return new ThreeD(0, 0, 0); } // Перегрузить логический оператор & для укороченного вычисления. public static ThreeD operator &(ThreeD op1, ThreeD op2) { if( ((op1.x != 0) && (op1.y != 0) && (op1.z != 0)) & ((op2.x != 0) && (op2.y != 0) && (op2.z != 0)) ) return new ThreeD(1, 1, 1); else return new ThreeD(0, 0, 0); } // Перегрузить логический оператор !. public static bool operator !(ThreeD op) { if(op) return false; else return true; } // Перегрузить оператор true. public static bool operator true(ThreeD op) { if((op.x != 0) || (op.y != 0) || (op.z != 0)) return true; // хотя бы одна координата не равна нулю else return false; } // Перегрузить оператор false. public static bool operator false(ThreeD op) { if((op.x == 0) && (op.y == 0) && (op.z == 0)) return true; // все координаты равны нулю else return false; } // Ввести координаты X, Y, Z. public void Show() { Console.WriteLine(x + ", " + у + ", " + z); } } class TrueFalseDemo { static void Main() { ThreeD a = new ThreeD(5, 6, 7); ThreeD b = new ThreeD(10, 10, 10); ThreeD с = new ThreeD(0, 0, 0); Console.Write("Координаты точки a: "); a.Show(); Console.Write("Координаты точки b: "); b.Show(); Console.Write("Координаты точки с: "); c.Show(); Console.WriteLine(); if(a) Console.WriteLine("Точка а истинна."); if(b) Console.WriteLine("Точка b истинна."); if(с) Console.WriteLine("Точка с истинна."); if(!a) Console.WriteLine("Точка а ложна."); if(!b) Console.WriteLine("Точка b ложна."); if(!с) Console.WriteLine("Точка с ложна."); Console.WriteLine(); Console.WriteLine("Применение логических операторов & и |"); if(a & b) Console.WriteLine("а & b истинно."); else Console.WriteLine("а & b ложно."); if(а & с) Console.WriteLine("а & с истинно."); else Console.WriteLine("а & с ложно."); if(а | b) Console.WriteLine("a | b истинно."); else Console.WriteLine("а | b ложно."); if(а | с) Console.WriteLine("а | с истинно."); else Console.WriteLine("а | с ложно."); Console.WriteLine(); // А теперь применить укороченные логические операторы. Console.WriteLine("Применение укороченных" + "логических операторов && и ||"); if(a && b) Console.WriteLine("a && b истинно."); else Console.WriteLine("а && b ложно."); if(а && с) Console.WriteLine("а && с истинно."); else Console.WriteLine("a && с ложно."); if(а || b) Console.WriteLine("a || b истинно."); else Console.WriteLine("a || b ложно."); if(a || c) Console.WriteLine("a || с истинно."); else Console.WriteLine("a || с ложно."); } }
Выполнение этой программы приводит к следующему результату. Координаты точки а: 5, 6, 7 Координаты точки b: 10, 10, 10 Координаты точки с: 0, 0, 0 Точка а истинна Точка b истинна Точка с ложна. Применение логических операторов & и | а & b истинно. a & с ложно. а | b истинно. а | с истинно. Применение укороченных логических операторов && и || a && b истинно. a && с ложно. а || b истинно. а || с истинно.
Рассмотрим более подробно, каким образом реализуются логические операторы & и |. Они представлены в следующем фрагменте кода. // Перегрузить логический оператор | для укороченного вычисления. public static ThreeD operator |(ThreeD op1, ThreeD op2) { if( ((op1.x != 0) || (op1.у != 0) || (op1.z != 0)) | ((op2.x != 0) || (op2.у != 0) || (op2.z != 0)) ) return new ThreeD(1, 1, 1); else return new ThreeD(0, 0, 0); } // Перегрузить логический оператор S для укороченного вычисления. public static ThreeD operator &(ThreeD op1, ThreeD op2) { if( ((op1.x != 0) && (op1.у != 0) && (op1.z != 0)) & ((op2.x != 0) && (op2.y != 0) && (op2.z != 0)) ) return new ThreeD(1, 1, 1); else return new ThreeD(0, 0, 0); }
Прежде всего обратите внимание на то, что методы обоих перегружаемых логиче ских операторов теперь возвращают объект типа ThreeD. И особенно обратите вни мание на то, как формируется этот объект. Если логическая операция дает истинный результат, то создается и возвращается истинный объект типа ThreeD, у которого хотя бы одна координата не равна нулю. Если же логическая операция дает ложный резуль тат, то соответственно создается и возвращается ложный объект. Таким образом, ре зультатом вычисления логического выражения а & b в следующем фрагменте кода: if (а & b) Console.WriteLine("а & b истинно."); else Console.WriteLine("а & b ложно.");
является объект типа ThreeD, который в данном случае оказывается истинным. А по скольку операторы true и false уже определены, то созданный объект типа ThreeD подвергается действию оператора true и в конечном итоге возвращается результат типа bool. В данном случае он равен true, а следовательно, условный оператор if успешно выполняется.
Благодаря тому что все необходимые правила соблюдены, укороченные операторы становятся доступными для применения к объектам ThreeD. Они действуют следующим образом. Первый операнд проверяется с помощью операторного метода operator true (для оператора ||) или же с помощью операторного метода operator false (для опе ратора &&). Если удается определить результат данной операции, то соответствующий перегружаемый оператор (& или |) далее не выполняется. В противном случае перегру жаемый оператор (& или | соответственно) используется для определения конечного ре зультата. Следовательно, когда применяется укороченный логический оператор && или ||, то соответствующий логический оператор & или | вызывается лишь в том случае, если по первому операнду невозможно определить результат вычисления выражения. В ка честве примера рассмотрим следующую строку кода из приведенной выше программы. if(а || с) Console.WriteLine("а || с истинно.");
В этой строке кода сначала применяется оператор true к объекту а. В данном слу чае объект а истинен, и поэтому использовать далее операторный метод | нет необхо димости. Но если переписать данную строку кода следующим образом: if(с || a) Console.WriteLine("с || а истинно.");
то оператор true был бы сначала применен к объекту с, который в данном случае ложен. А это означает, что для определения истинности объекта а пришлось бы далее вызывать операторный метод |.
Описанный выше способ применения укороченных логических операторов может показаться, на первый взгляд, несколько запутанным, но если подумать, то в таком применении обнаруживается известный практический смысл. Ведь благодаря пере грузке операторов true и false для класса компилятор получает разрешение на применение укороченных логических операторов, не прибегая к явной их перегрузке. Это дает также возможность использовать объекты в условных выражениях. И вообще, логические операторы & и | лучше всего реализовывать полностью, если, конечно, не требуется очень узко направленная их реализация. Операторы преобразования
Иногда объект определенного класса требуется использовать в выражении, вклю чающем в себя данные других типов. В одних случаях для этой цели оказывается пригодной перегрузка одного иди более операторов, а в других случаях – обыкно венное преобразование типа класса в целевой тип. Для подобных ситуаций в C# пред усмотрена специальная разновидность операторного метода, называемая оператором преобразования. Такой оператор преобразует объект исходного класса в другой тип. Операторы преобразования помогают полностью интегрировать типы классов в среду программирования на С#, разрешая свободно пользоваться классами вместе с другими типами данных, при условии, что определен порядок преобразования в эти типы.
Существуют две формы операторов преобразования: явная и неявная. Ниже они представлены в общем виде: public static explicit operator целевой_тип(исходный_тип v) {return значение;} public static implicit operator целевой_тип(исходный_тип v) {return значение;}
где целевойтип обозначает тот тип, в который выполняется преобразование; ис ходныйтип – тот тип, который преобразуется; значение – конкретное значение, приобретаемое классом после преобразования. Операторы преобразования возвра щают данные, имеющие целевой_тип, причем указывать другие возвращаемые типы данных не разрешается.
Если оператор преобразования указан в неявной форме (implicit), то преобразо вание вызывается автоматически, например, в том случае, когда объект используется в выражении вместе со значением целевого типа. Если же оператор преобразования указан в явной форме (explicit), то преобразование вызывается в том случае, когда выполняется приведение типов. Для одних и тех же исходных и целевых типов данных нельзя указывать оператор преобразования одновременно в явной и неявной форме.
Создадим оператор преобразования специально для класса ThreeD, чтобы проде монстрировать его применение. Допустим, что требуется преобразовать объект типа ThreeD в целое значение, чтобы затем использовать его в целочисленном выражении. Такое преобразование требуется, в частности, для получения произведения всех трех координат объекта. С этой целью мы воспользуемся следующей неявной формой опе ратора преобразования. public static implicit operator int(ThreeD op1) { return op1.x * op1.y * op1.z; }
Ниже приведен пример программы, демонстрирующей применение этого опера тора преобразования. // Пример применения оператора неявного преобразования. using System; // Класс для хранения трехмерных координат. class ThreeD { int х, у, z; // трехмерные координаты public ThreeD() { х = у = z = 0; } public ThreeD(int i, int j, int k) { x = i; у = j; z = k; } // Перегрузить бинарный оператор +. public static ThreeD operator +(ThreeD op1, ThreeD op2) { ThreeD result = new ThreeD); result.x = op1.x + op2.x; result.у = op1.у + op2.y; result.z = op1.z + op2.z; return result; } // Неявное преобразование объекта типа ThreeD к типу int. public static implicit operator int(ThreeD op1) { return op1.x * op1.у * op1.z; } // Вывести координаты X, Y, Z. public void Show() { Console.WriteLine(x + ", " + у + ", " + z); } } class ThreeDDemo { static void Main() { ThreeD a = new ThreeD(1, 2, 3); ThreeD b = new ThreeD(10, 10, 10); ThreeD с = new ThreeD(); int i; Console.Write("Координаты точки a: "); a.Show(); Console.WriteLine(); Console.Write("Координаты точки b: "); b.Show(); Console.WriteLine(); с = a + b; // сложить координаты точек а и b Console.Write("Результат сложения a + b: "); c.Show(); Console.WriteLine(); i = a; // преобразовать в тип int Console.WriteLine("Результат присваивания i = a: " + i); Console.WriteLine(); i = a * 2 – b; // преобразовать в тип int Console.WriteLine("Результат вычисления выражения a * 2 – b: " + i } }