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

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

    В завершение рассмотрим еще один пример, в котором используется перегрузка разных арифметических и побитовых операторов. Программа представлена ниже.

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

namespace pr108_1
{
    class Program
    {
        // Класс с перегрузкой арифметических и 
        // побитовых операторов: 
        class MyData {
            private int code; // Закрытое целочисленное поле 
            private char symb; // Закрытое символьное поле 
            private string text; // Закрытое текстовое поле 
            // Конструктор с тремя аргументами: 
            public MyData(int n, char s, string t) { 
                code = n;  // Значение целочисленного поля
                symb = s;  // Значение символьного поля
                text = t;  // Значение текстового поля
            }

            // Перегрузка метода ToString(): 
            public override string ToString() {
                // Локальная текстовая переменная: 
                string txt = "Поля объекта:\n"; 
                txt += "Числовое поле: " + code + "\n"; 
                txt += "Символьное поле: \'" + symb + "\'\n"; 
                txt += "Teкстовое поле: \"" + text + "\"\n";
                txt += "--------------------------";
	        // Результат метода: 
                return txt;
            }

            // Операторный метод для вычисления суммы объекта 
            // и целого числа:
            public static MyData operator+(MyData obj, int n) {
                return new MyData(+obj + n, -obj, ~obj);
            }

            // Операторный метод для вычисления разности объекта 
            // и целого числа:
            public static MyData operator-(MyData obj, int n) { 
                return new MyData(+obj - n,-obj, ~obj);
            }

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

            // Операторный метод для вычисления разности целого 
            // числа и объекта:
            public static int operator-(int n, MyData obj){ 
                return n - (+obj);
            }

            // Операторный метод для вычисления суммы объекта 
            // и текстовой строки:
            public static MyData operator+(MyData obj, string t) { 
                return new MyData(+obj, -obj, t);
            }

            // Операторный метод возвращает результатом текст: 
            public static string operator~(MyData obj){ 
                return obj.text;
            }

            // Операторный метод возвращает результатом число:
            public static int operator+(MyData obj){ 
                return obj.code;
            }

            // Операторный метод возвращает результатом символ: 
            public static char operator-(MyData obj){ 
                return obj.symb;
            }

            // Операторный метод возвращает результатом 
            // символ из текста:
            public static char operator>>(MyData obj, int k){ 
                return (~obj)[k];
            }

            // Операторный метод возвращает результатом 
            // символ из текста:
            public static char operator<<(MyData obj, int k){ 
                return (~obj)[(~obj).Length-k-1];
            }

            // Операторный метод возвращает результатом объект: 
            public static MyData operator^(MyData a, MyData b) { 
                string txt = ~a + " & " + ~b;	// Локальная переменная
                return new MyData(+a, -b, txt); // Результат метода
            }

            // Операторный метод для увеличения значения 
            // целочисленного поля объекта: 
            public static MyData operator++(MyData obj){ 
                obj.code += 10;	// Увеличение значения поля
                return obj;	// Результат метода
            }

            // Операторный метод для уменьшения значения 
            // целочисленного поля объекта: 
            public static MyData operator--(MyData obj){ 
                obj.code -= 10; // Уменьшение значения поля
                return obj; // Результат метода
            }
        }


        // Класс с главным методом: 
        static void Main()
        {
            // Создание объектов:
            MyData A = new MyData(100, 'A', "Alpha");
            MyData B = new MyData(200, 'B', "Bravo");
            // Новый объект:
            MyData C = A ^ B;
            // Проверка результата:
            Console.WriteLine(A);
            Console.WriteLine(B);
            Console.WriteLine(C);
            // Новый объект:
            C = B ^ A;
            // Проверка результата:
            Console.WriteLine(C);
            // Переменные:
            int n = +A;	 // Значение поля code объекта А
            char s = -A; //	Значение поля symb объекта А
            string t = ~A;	// Значение поля text объекта А
            // Проверка результата:
            Console.WriteLine("Объект А: поля {0}, \'{1}\' и \"{2}\"\n", n, s, t);
            // Увеличение значения поля code объекта А:
            A++;
            // Проверка результата:
            Console.WriteLine(A);
            // Увеличение значения поля code объекта А и 
            // проверка результата:
            Console.WriteLine(++A);
            // Уменьшение значения поля code объекта В и 
            // проверка результата:
            Console.WriteLine(B--);
            // Уменьшение значения поля code объекта В:
            --B;
            // Проверка результата:
            Console.WriteLine(B);
            //К объекту прибавляется число:
            C = A + 1000;
            // Проверка результата:
            Console.WriteLine(C);
            //Из объекта вычитается число:
            C = A - 100;
            // Проверка результата:
            Console.WriteLine(C);
            // Сумма и разность числа и объекта:
            Console.WriteLine("Сумма и разность: {0} и {1}\n", 2000 + A, 1000 - A); 
            // Прибавление к объекту текстовой строки:
            C = A + "Charlie";
            // Проверка результата:
            Console.WriteLine(C);
            // Посимвольное отображение значения текстового поля 
            // объекта С:
            for(int k=0; k<(~C).Length; k++){
                Console.Write((C >> k) + " ");
            }
            Console.WriteLine();
            // Символы из текстового поля объекта С 
            // отображаются в обратном порядке: 
            for(int k=0; k<(~C).Length; k++){
                Console.Write((C << k) + " ");
            }
            Console.WriteLine();
            // Прибавление объекта к текстовой строке: 
            t = "Объект C. " + C;
            // Проверка результата:
            Console.WriteLine(t);
            // Задержка:
            Console.ReadLine();
        }
    }
}
Архив проекта можно взять здесь.

    При выполнении этой программы получаем результат, представленный ниже.


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

    Код достаточно большой, но одновременно и несложный. Мы прокомментируем лишь основные моменты. Основу кода составляет класс MyData. У класса есть три закрытых поля:

У класса всего один конструктор с тремя аргументами, которые определяют значения полей создаваемого объекта. Также в классе описан метод ToString(), возвращающий результатом текстовую строку с информацией о значении полей объекта. Для удобства восприятия информации текстовая строка содержит несколько инструкций \n (для отображения текста в новой строке консоли), а в конце отображается импровизированная линия из дефисов.


В программе в качестве идентификатора текстового типа использовано ключевое слово string. Напомним, что идентификатор string является псевдонимом для инструкции System.String. На практике для обозначения текстового типа обычно используют идентификатор string.

    Для доступа к полям мы перегружаем унарные операторы +, - и ~. Если obj - объект класса MyData, то значением выражения +obj является значение поля code объекта obj, значением выражения -obj является значение поля symb объекта obj, а значением выражения ~obj является текстовое значение поля text объекта obj. Именно такие ссылки на поля в основном используются в программном коде класса MyData. Кроме этого определяются такие операции с объектами класса MyData:

    Текст из текстового поля объекта obj возвращается выражением -obj. Символ с индексом k в этом текстовом значении вычисляется выражением (-obj)[k]. Круглые скобки нужны для изменения порядка применения оператора - и квадратных скобок.

    Если под k подразумевать индекс, отсчитываемый с конца текстовой строки, то он соответствует "обычному" (отсчитываемому с начала строки) индексу (-obj).Length-k-1. Здесь следует учесть, что количество символов в тексте вычисляется выражением (-obj).Length. Полная ссылка на нужный символ выглядит как (-obj)[(-obj).Length-k-1].

    В главном методе программы проверяется работа перегруженных операторов. Мы создаем два объекта А и В класса МуData, после чего выполняем некоторые операции с ними. На что стоит обратить внимание? Наиболее интересные позиции.


Если оператор в принципе перегружаем, то выполнять перегрузку можно по-разному. Другими словами, конкретный способ перегрузки оператора определяется решаемой задачей и фантазией программиста. Однако есть общая рекомендация, состоящая в том, что перегрузку операторов желательно выполнять с учетом "основного" назначения оператора. Например, если перегружается бинарный оператор "плюс" для объектов определенного класса, то желательно, чтобы определяемая при перегрузке операция могла интерпретироваться в некотором смысле как сложение объектов. Но это лишь рекомендация, не более того.

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




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