Перегрузка стандартных операторов C#

Перезагрузка операторов +, -, ++ и --.

 

Создадим класс, над которым мы и будем ставить наши "Эксперименты". Очень хорошо для этого подойдет класс Money (деньги):
  

  class Money
    {
        private int rub; //рубль
        private int kop; //копейка

        public Money()
        {
            rub = 0;
            kop = 0;
        }

        public Money(int r, int k)
        {
            rub = r;
            kop = k % 100;
        }

        public void howmuch()
        {
            Console.WriteLine("У вас " + rub + " рублей " + kop + " копеек");
        }

    }

 

Вот наш класс, который содержит 2 скрытых поля: rub и kop. Данный класс имеет 2 конструктора. Первый конструктор присваивает полям нулевые значения, а второй инициализирует их начальными значениями. Запись %100 означает остаток от деления на 100. С помощью такой записи мы защищаем себя от ввода заведомо ложного значения (напомню, что в рубле 100 копеек). Можно было написать защиту и получше, но сейчас мы не будем тратить на это время.

А сейчас еще один пример, того, как можно было бы использовать данный класс:

            Money m1 =  new Money(1, 50);
            Money m2 =  new Money(1, 50);
            Money m3 = m1 + m2;
            m3.howmuch();

 

Было бы логично, чтобы данная программа вывела, что у нас 3 рубля 0 копеек, но пока она такого сделать не может, т.к. понятия не имеет, как складывать деньги, т.е. не умеет пользоваться оператором +. Но мы то с вами умеем, поэтому давайте ее научим:
    

    public static Money operator +(Money m1, Money m2)
        {
            Money tmp = new Money();
            tmp.rub = m1.rub + m2.rub;
            tmp.rub += (int)((m1.kop + m2.kop) / 100);
            tmp.kop = (m1.kop + m2.kop) % 100;
            return tmp;
        }


Этот метод нужно вставить в наш класс Money. Здесь мы встречаемся с новым ключевым словом - operator. Обратите внимание, что наш перегруженный метод возвращает объект типа Money. Это позволяет нам писать выражения типа:
  m4 = m1 + m2 + m3 + ... + mN;

Давайте поясним что же происходит в перегруженном методе. Сперва мы создаем объект tmp. Поскольку он создается с помощью конструктора по умолчанию, то и рубли и копейки в нем равны нулю. В следующей строке мы складываем рубли. А дальше весьма интересная конструкция. Просто сложить рубли не достаточно, нужно учесть тот факт, что при сложении копеек их может оказаться больше 100. Поэтому в следующей строке мы выполняем следующее:

а) складываем копейки
б) делим их на 100
в) с помощью приведения типов отбрасываем дробную часть
г) добавляем получившийся результат к рублям

Можно было написать и по-другому, например, так:
    if ((m1.kop + m2.kop) >= 100) tmp.rub++;

Ну а дальше мы складываем копейки. И, наконец, возвращаем наш объект. После чего можно смело складывать наши денежки в одну кучу.

Ну а теперь научим наш класс вычитать денежки (это немного сложнее, т.к. нужно учитывать тот факт, что деньги не могут быть отрицательной величиной):

        public static Money operator -(Money m1, Money m2)
        {
            Money tmp = new Money();
            tmp.rub = m1.rub - m2.rub;
            tmp.kop = m1.kop - m2.kop;
            if (tmp.kop < 0) tmp.rub--;
            tmp.kop = Math.Abs(tmp.kop);
            if (tmp.rub < 0)
            {
                tmp.rub = 0;
                tmp.kop = 0;
            }
            return tmp;
        }

 

Вот и все. Выглядит достаточно сложно, но зато пользоваться очень удобно. Нам встретился метод Math.Abs, с помощью такой конструкции мы вызываем метод Abs, который находится в пространстве имен Math. Метод Abs - возвращает абсолютное значение (т.е. модуль числа). В конце работы нашего перегруженного оператора - мы проверяем поле rub, если оно оказалось отрицательным, то это означает, что второй операнд больше первого, поэтому возвращаем нули. Надеюсь, что вы разберетесь, как это "чудо" работает.

Ну и напоследок, хотелось бы рассказать про перегрузку операторов ++ и --. В отличие от операторов + и - эти операции являются унарными, т.е. применимы только к одному объекту. Давайте договоримся, что конструкция m1++ (где m1 - экземпляр класса Money) будет добавлять один рубль, а конструкция m1-- вычитать рубль. Если у нас меньше одного рубля, то операция -- обнулит поля rub и kop. Итак, приступим к реализации:

        public static Money operator ++(Money m1)
        {
            m1.rub++;
            return m1;
        }

        public static Money operator --(Money m1)
        {
            if (m1.rub == 0)
            {
                m1.rub = 0;
                m1.kop = 0;
            }
            else
            {
                m1.rub--;
            }
            return m1;
        }


После этого вы можете смело писать:

            Money m1 = new Money(1, 60);
            m1--;
            m1.howmuch();

 

На экран будет выведено, что у вас 0 рублей 60 копеек.


 

 

 
13.12.2008

Отзывы и комментарии

 


 
Тема
Ваше имя
Почтовый адрес
Текст сообщения
Ключ защиты:
Защита от спама
 
 
 
 
10.12  .NET Reactor
15.11  n
15.11  C# ClickOnce
 
01.08  Task Context
01.08  XLSX в Mono