На этом шаге мы рассмотрим особенности перегрузки таких операторов.
Бинарные операторы & и | и унарный оператор ! могут перегружаться произвольным образом. Причем тип результата для соответствующих операторных методов не обязательно должен быть логическим значением. Операторы && и || не перегружаются (то есть их нельзя перегрузить). Но в классе можно так перегрузить операторы & и |, а также операторы true и false, что с объектами класса станет возможно использовать операторы && и ||. Именно такой способ перегрузки операторов &, |, true и false мы и рассмотрим.
Чтобы уловить идею, на которой основан весь подход по перегрузке операторов, имеет смысл проанализировать способ вычисления выражений вида А && В и А || В. Мы исходим из того, что операнды А и В являются объектами некоторого класса (в котором мы планируем перегружать операторы).
Итак, при вычислении выражения А && В первый операнд А проверяется на предмет ложности. Для этого вызывается операторный метод для оператора false. Если операнд А "ложный" (операторный метод operator false() возвращает значение true), то результатом выражения А && В возвращается операнд А. Если операнд А "ложным" не признается (операторный метод operator false() возвращает значение false), то результатом выражения А && В возвращается значение выражения А&В.
При вычислении значения выражения А || В операнд А проверяется на предмет "истинности", и для этого вызывается операторный метод operator true(). Если метод возвращает значение true, то результатом выражения А || В возвращается операнд А. Если операторный метод operator true() возвращает значение false, то результатом выражения А || В возвращается результат выражения А | В.
Отсюда становятся понятны принципы, определяющие способ перегрузки операторов &, |, true и false для возможности использования операторов && и ||. Они таковы:
Как эта схема реализуется на практике, показано в примере программы ниже.
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace pr114_1 { // Класс с перегрузкой операторов: class MyClass{ // Символьное поле: public char symb; // Конструктор с одним аргументом: public MyClass(char s) { symb = s; // Значение поля } // Перегрузка оператора true: public static bool operator true(MyClass obj){ switch(obj.symb) { case 'A': case 'E': case 'T': case 'O': case 'U': case 'Y': return true; default: return false; } } // Перегрузка оператора false: public static bool operator false(MyClass obj){ if(obj) return obj.symb=='Y'; else return true; } // Перегрузка оператора &: public static MyClass operator&(MyClass a, MyClass b){ if(a) return b; else return a; } // Перегрузка оператора | public static MyClass operator|(MyClass a, MyClass b){ if (a) return a; else return b; } } // Класс с главным методом: class Program { static void Main() { // Создание объектоз: MyClass A = new MyClass('A'); MyClass B = new MyClass('B'); MyClass E = new MyClass('E'); MyClass Y = new MyClass('Y'); // Использование логических операторов: Console.WriteLine("Выражение A&&B: {0}", (A&&B).symb); Console.WriteLine("Выражение B&&A: {0}", (B&&A).symb); Console.WriteLine("Выражение A&&E: {0}", (A&&E).symb); Console.WriteLine("Выражение E&&A: {0}", (E&&A).symb); Console.WriteLine("Выражение A&&Y: {0}", (A&&Y).symb); Console.WriteLine("Выражение Y&&A: {0}", (Y&&A).symb); Console.WriteLine("Выражение A||B: {0}", (A||B).symb); Console.WriteLine("Выражение В||A: {0}", (B||A).symb); Console.WriteLine("Выражение A||E: {0}", (A||E).symb); Console.WriteLine("Выражение E||A: {0}", (E||A).symb); Console.WriteLine("Выражение А||Y: {0}", (A||Y).symb); Console.WriteLine("Выражение Y||A: {0}", (Y||A).symb); // Задержка: Console.ReadLine(); } } }
Результат выполнения программы представлен ниже.
Рис.1. Результат выполнения программы
Класс MyClass имеет одно поле (символьное поле с названием symb) и конструктор с одним аргументом (определяет значение поля). В классе описаны четыре операторных метода. В теле операторного метода operator true() с помощью оператора выбора проверяется значение символьного поля объекта-операнда. Если это большая английская гласная буква, то метод возвращает результатом true. В противном случае результат равен false.
В теле операторного метода operator false() есть условная конструкция. В ней условием указан объект obj (аргумент метода). Если объект "истинный" (а это определяется вызовом операторного метода operator true()), то результатом метода operator false() возвращается значение выражения obj.symb=='Y' (равно false за исключением случая, когда значение поля равно 'Y'). Если объект obj не является "истинным", то результатом метода operator false() возвращается значение true.
Операторный метод operator&() описан так, что если первый аргумент (объект а класса MyClass) "истинный", то результатом возвращается ссылка на второй аргумент (объект b класса MyClass). Если первый операнд не "истинный", то результатом возвращается ссылка на него.
Операторный метод operator|() возвращает ссылку на первый операнд, если он "истинный". Если первый операнд не "истинный", то результатом метода возвращается ссылка на второй операнд.
В главном методе программы создается четыре объекта (название объекта совпадает с символом, являющимся значением символьного поля объекта). Объекты используются для вычисления выражений на основе операторов && и ||. Для проверки выводится значение поля symb объекта-результата.
На следующем шаге мы рассмотрим перегрузку операторов приведения типов.