Шаг 114.
Язык программирования C#. Начала
Перегрузка операторов. Перегрузка логических операторов

    На этом шаге мы рассмотрим особенности перегрузки таких операторов.

    Бинарные операторы & и | и унарный оператор ! могут перегружаться произвольным образом. Причем тип результата для соответствующих операторных методов не обязательно должен быть логическим значением. Операторы && и || не перегружаются (то есть их нельзя перегрузить). Но в классе можно так перегрузить операторы & и |, а также операторы 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.


Получается, что если значением поля объекта является один из символов 'А', 'Е', 'I', 'O', 'U' или 'Y' то объект интерпретируется как "истинный". Как "ложный" интерпретируется любой не являющийся "истинным" объект, а также объект со значением 'Y' символьного поля. Другими словами, если у объекта поле равно 'Y', то такой объект интерпретируется и как "истинный", и как "ложный". Такой вот парадокс (законный тем не менее).

    Операторный метод operator&() описан так, что если первый аргумент (объект а класса MyClass) "истинный", то результатом возвращается ссылка на второй аргумент (объект b класса MyClass). Если первый операнд не "истинный", то результатом возвращается ссылка на него.

    Операторный метод operator|() возвращает ссылку на первый операнд, если он "истинный". Если первый операнд не "истинный", то результатом метода возвращается ссылка на второй операнд.

    В главном методе программы создается четыре объекта (название объекта совпадает с символом, являющимся значением символьного поля объекта). Объекты используются для вычисления выражений на основе операторов && и ||. Для проверки выводится значение поля symb объекта-результата.


Кратко проанализируем результат выполнения операций с операторами && и ||.

    На следующем шаге мы рассмотрим перегрузку операторов приведения типов.




Предыдущий шаг Содержание Следующий шаг