C#. Перевантаження бінарних операторів

Перевантаження бінарних операторів. Перевантаження операторів +, , *, /, %. Вкладення довільної логіки при перевантаженні

Перед вивченням даної теми рекомендується ознайомитись з наступною темою:


Зміст


Пошук на інших ресурсах:

1. Особливості перевантаження бінарних операторів

У мові C# допускається перевантажувати наступні бінарні оператори:

  • + – додавання (a + b);
  • – віднімання (a – b);
  • * – множення (a * b);
  • / – ділення (a / b);
  • % – оператор взяття остачі від ділення. Може бути перевантажений на власний розсуд;
  • & – побітове логічне “І”;
  • | – побітове логічне “АБО”;
  • ^ – побітове додавання по модулю 2;
  • <, > – оператори порівняння (менше, більше). У класі ці оператори обов’язково перевантажуються парою (обидва);
  • <=, >= – оператори порівняння (менше або рівне, більше або рівне). Ці оператори перевантажуються парою;
  • ==, != – оператори порівняння (дорівнює, не дорівнює). Перевантажуються парою в класі.

При перевантаженні бінарних операторів створюється статичний метод, який отримує 2 параметри. Тип цих параметрів є типом класу, в якому реалізується метод, що перевантажує оператор.

У найбільш загальному випадку перевантаження бінарного оператора в класі з іменем ClassName має вигляд:

class ClassName
{
  public static ClassName operator op(ClassName obj1, ClassName obj2)
  {
    // Дії, які потрібно виконати при виклику obj1 op obj2
    // ...
  }
}

тут

  • op – один з стандартних бінарних операторів, які можна перевантажувати (+, , ==, > і т.д.);
  • obj1 – екземпляр, що знаходиться зліва від оператора op;
  • obj2 – екземпляр, що знаходиться справа від оператора op.

Після перевантаження, екземпляри obj1 та obj2 можна поєднувати оператором op у більш наочному вигляді

obj1 op obj2

Наприклад, якщо перевантажити оператор +, то виклик відповідного методу буде

obj1 + obj2

 

2. Перевантаження бінарних операторів +, , *, /. Приклад

Задано клас Complex, що визначає комплексне число. У класі міститься мінімально-можливий набір методів та властивостей для повноцінного функціонування.
У класі Complex перевизначено оператори +, –, *, / які реалізують відповідно додавання, віднімання, множення та ділення двох комплексних чисел.

using System;

namespace ConsoleApp6
{
  class Complex
  {
    // Внутрішні поля класу
    private double re, im;

    // Конструктор
    public Complex(double re, double im)
    {
      this.re = re;
      this.im = im;
    }

    // Властивості доступу до внутрішніх полів
    public double Re
    {
      get { return re; }
      set { re = value; }
    }

    public double Im
    {
      get { return im; }
      set { im = value; }
    }

    // Операторний метод, що перевантажує бінарний оператор '+',
    // реалізує додавання комплексних чисел
    public static Complex operator+(Complex cm1, Complex cm2)
    {
      return new Complex(cm1.re + cm2.re, cm1.im + cm2.im);
    }

    // Операторний метод, що перевантажує бінарний оператор '-',
    // реалізує віднімання комплексних чисел
    public static Complex operator-(Complex cm1, Complex cm2)
    {
      return new Complex(cm1.re - cm2.re, cm1.im - cm2.im);
    }

    // Метод, що перевантажує оператор '*'
    // реалізує множення комплексних чисел
    public static Complex operator*(Complex cm1, Complex cm2)
    {
      return new Complex(cm1.re * cm2.re - cm1.im * cm2.im, 
        cm1.re * cm2.im + cm1.im * cm2.re);
    }

    // Перевантаження оператора '/' - ділення комплексних чисел
    public static Complex operator/(Complex cm1, Complex cm2)
    {
      double denom = cm2.re * cm2.re + cm2.im * cm2.im;
      return new Complex((cm1.re * cm2.re + cm1.im * cm2.im) / denom,
        (cm1.im * cm2.re - cm1.re * cm2.im) / denom);
    }

    // Метод, що виводить стан поточного екземпляру
    public void Print(string msg)
    {
      Console.Write(msg + " => ");
      Console.Write(re);
      if (im >= 0)
        Console.Write("+");
      Console.WriteLine(im.ToString() + "*j");
    }
  }

  internal class Program
  {
    static void Main(string[] args)
    {
      // 1. Створити 2 об'єкти типу Complex
      Complex cm1 = new Complex(3, 5);
      Complex cm2 = new Complex(2, -4);

      // 2. Вивести об'єкти
      cm1.Print("cm1");
      cm2.Print("cm2");

      // 3. Додати об'єкти
      Complex cm3;
      cm3 = cm1 + cm2; // викликається метод, що перевантажує оператор '+'
      cm3.Print("cm1 + cm2");

      // 4. Відняти - виклик методу Complex.operator-()
      (cm1 - cm2).Print("cm1-cm2");

      // 5. Помножити
      cm3 = cm1 * cm2;
      cm3.Print("cm1 * cm2");

      // 6. Поділити
      cm3 = cm1 / cm2;
      cm3.Print("cm1 / cm2");

      // 7. Використання операторів +=, -=, *=, /=
      Complex cm4 = new Complex(1, 1);
      cm4 += cm1; // => cm4 = cm4 + cm1;
      cm4.Print("cm4");

      Complex cm5 = new Complex(2, 3);
      cm5 *= cm2; // => cm5 = cm5 * cm2
      cm5.Print("cm5");

      Console.ReadKey();
    }
  }
}

Результат

cm1 => 3+5*j
cm2 => 2-4*j
cm1 + cm2 => 5+1*j
cm1-cm2 => 1+9*j
cm1 * cm2 => 26-2*j
cm1 / cm2 => -0.7+1.1*j
cm4 => 4+6*j
cm5 => 16-2*j

 

3. Особливості перевантаження операторів +=, -=, *=, /=, %=

Скорочені оператори присвоєння +=, -=, *=, /=, %= та інші подібні вважаються перевантаженими, як тільки перевантажені відповідні їм оператори +, , *, /, % та інші.

На прикладі класу Point перевантажуються оператори + та . Потім демонструється виклик відповідних операторів +=, –= для екземплярів класу Point.

Перевантажені оператори + та виконують додавання та віднімання координат точок.

using System;

namespace ConsoleApp6
{
  // Клас, що описує точку на координатній площині
  class Point
  {
    // Внутрішні змінні
    private int x, y;

    // Конструктор
    public Point(int x, int y)
    {
      this.x = x;
      this.y = y;
    }

    // Властивості доступу до координат точок
    public int X
    {
      get { return x; }
    }

    public int Y
    {
      get { return y; }
    }

    // Метод, що виводить поточні значення x, y
    public void Print(string msg)
    {
      Console.WriteLine(msg + " => " + "( " + x + "; " + y + ")");
    }

    // Перевантажені оператори '+' та '-'
    public static Point operator+(Point p1, Point p2)
    {
      return new Point(p1.x + p2.x, p1.y + p2.y);
    }

    public static Point operator-(Point p1, Point p2)
    {
      return new Point(p1.x - p2.x, p1.y - p2.y);
    }
  }

  internal class Program
  {
    static void Main(string[] args)
    {
      // 1. Створити 2 екземпляри класу Point
      Point pt1 = new Point(3, 8);
      Point pt2 = new Point(4, 9);

      // 2. Використати оператор += для обчислення суми точок pt1 та pt2
      pt1 += pt2; // => pt1 = pt1 + pt2; - виконується: pt1 = Point.operator+(pt1, pt2)
      pt1.Print("pt1");

      // 3. Викликати оператор -= для обчислення різниці pt2 = pt2 - pt1;
      pt2 -= pt1; // pt2 = Point.operator(pt2, pt1);
      pt2.Print("pt2");

      Console.ReadKey();
    }
  }
}

Після перевантаження операторів + та у класі Point у функції main() викликаються відповідні оператори += та -= в рядках

pt1 += pt2;
pt2 -= pt1;

Після виконання програма видає наступний результат

pt1 => ( 7; 17)
pt2 => ( -3; -8)

 

4. Приклад перевантаження оператора %. Визначення середнього арифметичного двох масивів. Програмування довільної логіки при перевантаженні операторів

У методи, що перевантажують оператори можна вкладати код, що реалізує будь-які дії. Не обов’язково код перевантажуваного методу повинен відповідати призначенню оператора, який цей метод перевантажує.
Оператор % визначає остачу від ділення цілочисельних значень. Однак, у нашому випадку реалізована друга логіка. Визначається середнє арифметичне двох операндів, які є масивами типу ArrayDouble. Цей приклад носить демонстраційний характер і показує як по різному можна програмувати логіку методів, що перевизначають оператори.

Слід звернути увагу, що операторний метод operator%() повертає тип double а не ArrayDouble.

using System;

namespace ConsoleApp6
{
  // Масив чисел з плаваючою комою
  class ArrayDouble
  {
    private double[] AD;

    // Конструктор
    public ArrayDouble(double[] _AD)
    {
      // Копіювання AD = _AD
      AD = new double[_AD.Length];
      for (int i = 0; i < AD.Length; i++)
        AD[i] = _AD[i];
    }

    // Метод, що виводить масив AD
    public void Print(string msg)
    {
      Console.Write(msg + " => ");
      for (int i = 0; i < AD.Length; i++)
        Console.Write(AD[i] + " ");
      Console.WriteLine();
    }

    // Перевантаження оператора %.
    // Визначення середнього арифметичного двох масивів-операндів.
    // Звернути увагу: метод повертає double а не ArrayDouble
    public static double operator%(ArrayDouble AD1, ArrayDouble AD2)
    {
      // 1. Обчислити суму елементів масивів
      double res = 0;
      for (int i = 0; i < AD1.AD.Length; i++)
        res += AD1.AD[i];
      for (int i = 0; i < AD2.AD.Length; i++)
        res += AD2.AD[i];

      // 2. Повернути середнє арифметичне
      return res / (AD1.AD.Length + AD2.AD.Length);
    }
  }

  internal class Program
  {
    static void Main(string[] args)
    {
      // 1. Створити 2 масиви типу double[]
      double[] A1 = { 2.4, 3.1, 0.8, -2.2, 0.9, 11.6 };
      double[] A2 = { 3.8, 11.7, -4.4, 0.8 };

      // 2. На основі масивів створити 2 екземпляри
      ArrayDouble AD1 = new ArrayDouble(A1);
      ArrayDouble AD2 = new ArrayDouble(A2);

      // 3. Вивести масиви для контролю
      AD1.Print("AD1");
      AD2.Print("AD2");

      // 4. Використати перевантажений оператор % для
      // обчислення середнього арифметичного
      double average = AD1 % AD2;
      Console.WriteLine("AD1 % AD2 = {0:f3}", average);

      Console.ReadKey();
    }
  }
}

Результат

AD1 => 2.4 3.1 0.8 -2.2 0.9 11.6
AD2 => 3.8 11.7 -4.4 0.8
AD1 % AD2 = 2.850

 


Споріднені теми