Шаг 107.
Язык программирования C#. Начала. Перегрузка операторов. Перегрузка арифметических и побитовых операторов (продолжение)

    На этом шаге мы расширим пример, приведенный на предыдущем шаге.

    Еще одна версия программы с перегрузкой оператора "плюс" представлена в примере ниже. На этот раз в классе MyClass представлено несколько операторных методов с названием operator+.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace pr107_1
{
    class Program
    {
        // Класс с перегрузкой оператора "плюс": 
        class MyClass
        {
            // Целочисленное поле: 
            public int number;
            // Конструктор с одним аргументом: 
            public MyClass(int n)
            {
                // Присваивание значения полю: 
                number = n;
            }

            // Переопределение метода ToString(): 
            public override String ToString()
            {
                // Результат метода: 
                return "Поле number: " + number;
            }

            // Операторный метод для вычисления суммы двух объектов: 
            public static MyClass operator +(MyClass a, MyClass b)
            {
                // Целочисленная локальная переменная: 
                int m = a.number + b.number;
                // Создание объекта класса:
                MyClass t = new MyClass(m);
                // Результат метода: 
                return t;
            }

            // Операторный метод для вычисления суммы объекта 
            //и целого числа:
            public static MyClass operator +(MyClass a, int x)
            {
                // Целочисленная локальная переменная: 
                int m = a.number + x;
                // Результат метода: 
                return new MyClass(m);
            }

            // Операторный метод для вычисления суммы целого 
            // числа и объекта:
            public static MyClass operator +(int x, MyClass a)
            {
                // Результат метода: 
                return a + x;
            }

            // Операторный метод для унарного оператора "плюс": 
            public static int operator +(MyClass a)
            {
                // Результат метода: 
                return a.number;
            }
        }

        // Класс с главным методом:    
        static void Main()
        {
            // Создание объектов:
            MyClass A = new MyClass(100);
            MyClass B = new MyClass(200);
            // Вычисление суммы объектов:
            MyClass C = A + B;
            // Проверка результата:
            Console.WriteLine(A);
            Console.WriteLine(B);
            Console.WriteLine(C);
            // Вычисление суммы объекта и целого числа:
            C = A + 1;
            // Проверка результата:
            Console.WriteLine(C);
            // Вычисление суммы целого числа и объекта:
            C = 10 + A;
            // Проверка результата:
            Console.WriteLine(C);
            Console.Write("Унарный оператор: ");
            // Используется унарный "плюс":
            Console.WriteLine(+C); 
            int num = (+A) + (+B);
            // Проверка результата:
            Console.WriteLine("Сумма чисел: " + num);
            // Задержка:
            Console.ReadLine();
        }
    }
}
Архив проекта можно взять здесь.

    При выполнении программы получаем такой результат.


Рис.1. Результат выполнения программы

    В этой программе (но сравнению с предыдущим примером) класс MyClass немного "расширился". Кроме целочисленного поля number и конструктора с одним аргументом, у класса MyClass теперь есть переопределенный метод ToString(). Результатом метод возвращает текст со значением поля number объекта класса. Но нас конечно же интересуют в первую очередь операторные методы. Их в классе четыре. Все они называются operator+. Отличаются методы типом и количеством аргументов, а также типом возвращаемого результата. Версия метода с двумя аргументами, являющимися объектами класса MyClass, результатом возвращает объект класса MyClass. То есть теперь, если мы будем складывать два объекта класса MyClass, то в результате получим новый объект класса MyClass.


В версии программы из предыдущего шага при сложении двух объектов класса MyClass результатом получали целое число.

    В теле метода командой

  int m = a.number + b.number;
вычисляется сумма полей number объектов A и B, переданных аргументами методу (то есть операндов выражения, которое будет обрабатываться этим операторным методом). После этого командой
  MyClass t = new MyClass(m);
создается новый объект класса MyClass. Значение поля number этого объекта равно сумме значений полей объектов A и B. Созданный таким образом объект возвращается результатом операторного метода.

    Еще одна версия операторного метода с названием operator+ подразумевает, что аргументами (операндами) являются объект класса MyClass и целое число.


Порядок аргументов в операторном методе и, соответственно, порядок операндов в выражении с перегружаемым оператором имеет значение. Ситуации, когда к объекту прибавляется число и когда к числу прибавляется объект, обрабатываются разными версиями операторного метода для оператора сложения. Поэтому в программе мы отдельно описываем версию операторного метода, в которой первый аргумент - объект, а второй - целое число, а в еще одной версии операторного метода первый объект - целое число, а второй аргумент - объект. Мы определяем результат сложения числа и объекта так же, как и результат сложения объекта и числа. Но в общем случае результат таких операций может быть различным.

    Результатом выражения, в котором к объекту класса MyClass прибавляется целое число, является объект класса MyClass. Его поле number равно сумме значений поля number первого аргумента (объект A) и второго целочисленного аргумента (обозначен как х). Поэтому в теле метода командой

  int m = a.number + x;
вычисляется сумма значения поля объекта и целого числа, а затем результатом метода возвращается объект, созданный инструкцией
  new MyClass(m);


Инструкцией
  new MyClass(m);
создается новый объект, но ссылка на него в объектную переменную не записывается. Такие объекты называют анонимными. В данном случае выражение new MyClass(m) указано после инструкции return. При выполнении инструкции new MyClass(m), как отмечалось выше, создается новый объект. А результатом инструкции является ссылка на этот созданный объект. Поэтому получается, что операторный метод результатом возвращает ссылку на созданный объект, что нам и нужно.

    В принципе, мы могли бы объявить объектную переменную класса MyClass, записать в нее ссылку на созданный объект, а затем указать данную объектную переменную в return-инструкции. Так мы поступили в версии операторного метода, в которой оба аргумента - объекты класса MyClass. В данном случае мы обошлись без вспомогательной объектной переменной.


    Еще в программе описана версия операторного метода для оператора "плюс", в которой первый аргумент целочисленный (обозначен как х), а второй (обозначен как A) является объектом класса MyClass. В теле этой версии метода всего одна команда

  return a + x;      .
И это примечательный момент. Результатом метода возвращается сумма объекта и целого числа. Выражение а+х имеет смысл, только если в классе описана версия операторного метода для оператора "плюс", в которой первый аргумент является объектом, а второй аргумент - целое число. Такая версия метода в классе MyClass описана. Именно она вызывается для вычисления значения выражения а+х.


Образно выражаясь, операторный метод для вычисления суммы целого числа и объекта мы определяем так: при вычислении суммы целого числа и объекта нужно вычислить сумму этого объекта и целого числа. В этом смысле операция вычисления суммы целого числа и объекта является коммутативной: не имеет значения, в каком порядке указаны операнды. Но это не есть общее правило. Просто мы так определили правила сложения объектов и чисел. В принципе, мы могли определить их иначе, и результат сложения объекта и числа отличался бы (не только по значению, но и по типу результата) от результата сложения целого числа и объекта.

    В классе MyClass есть версия операторного метода operator+() с одним аргументом (объект класса MyClass). Эта версия операторного метода перегружает унарный оператор "плюс". Результат выражения с унарным оператором "плюс" является целым числом - значением поля number объекта-операнда.

    В главном методе программы проверяется функциональность описанных в классе MyClass операторных методов. Там создается два объекта (А и В) класса MyClass со значениями соответственно 100 и 200 для поля number. Объектная переменная С класса MyClass значение получает при выполнении команды

  MyClass C = A + B;     .
То есть это сумма двух объектов. Результатом является новый объект, поле number которого равно 300 (сумма полей объектов А и В). При выполнении команды
  C = A + 1; 
получаем новый объект (ссылка на который записывается в переменную С), и значение поля number этого объекта равно 101 (сумма поля number объекта А и второго числового операнда 1). Наконец, при выполнении команды
  C = 10 + A;
создается еще один объект со значением поля 110. Ссылка на объект записывается в переменную С. Значение поля вычисляется как сумма первого операнда 10 и значения поля number объекта А.

    Значением выражения является целое число - это значение поля number объекта С. Здесь при вычислении выражения вызывается версия операторного метода operator+() для унарного оператора "плюс". Поэтому при выполнении команды

  Console.WriteLine(+C); 
в консольное окно выводится значение поля number объекта С. А вот при выполнении команды
  Console.WriteLine(C);
в консоли отображается текст, возвращаемый методом ToString() (то есть здесь речь идет о преобразовании объекта С к текстовому формату).

    Аналогично, значением выражения есть значение поля number объекта А, а значением выражения есть значение поля number объекта В. Поэтому при выполнении команды

  int num = (+A) + (+B); 
целочисленная переменная num получает значением сумму полей объектов A и B.

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




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