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

Перевантаження операторів порівняння ==, !=, <, >, <=, >=. Перевантаження логічних побітових операторів &, |, ^


Зміст


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

1. Перевантаження бінарних операторів порівняння ==, !=. Приклад

Оператори порівняння ==, != можна перевантажувати в класі. Особливість цих операторів полягає в тому, що потрібно реалізовувати обидва оператори одночасно.

Демонструється використання бінарних операторів порівняння для класу ArrayRange який реалізує масив цілих чисел, що знаходяться в заданому діапазоні. У класі перевантажуються оператори == та !=. Ці оператори здійснюють поелементне порівняння двох об’єктів типу ArrayRange.

Обов’язковим є перевантаження цих операторів у парі. Якщо перевантажується оператор ==, то потрібно перевантажувати оператор !=.

using System;

namespace ConsoleApp6
{
  class ArrayRange
  {
    // Внутрішнє поле - масив
    private int[] A;
    private int min; // мінімальне значення
    private int max; // максимальне значення

    // Конструктор
    public ArrayRange(int[] _A, int _min, int _max)
    {
      // Встановити межі
      if (_min <= _max)
      {
        min = _min; max = _max;
      }

      if (_min >= _max)
      {
        min = _max; max = _min;
      }

      // Зробити копію з вхідного масиву _A
      A = new int[_A.Length];
      for (int i = 0; i < A.Length; i++)
      {
        if (_A[i] < min)
          A[i] = min;
        else
        if (_A[i] > max)
          A[i] = max;
        else
          A[i] = _A[i];
      }
    }

    // Метод, що виводить внутрішній масив
    public void Print(string msg)
    {
      Console.WriteLine(msg);
      for (int i = 0; i < A.Length; i++)
        Console.Write(A[i] + " ");
      Console.WriteLine();
      Console.WriteLine("-----------------------------");
    }

    // Метод, що повертає посилання на масив A
    public int[] Get() { return A; }

    // Метод, що перевантажує оператор ==
    public static bool operator==(ArrayRange A1, ArrayRange A2)
    {
      // 1. Порівняння довжин
      if (A1.A.Length != A2.A.Length)
        return false;

      // 2. Поелементне порівняння
      for (int i = 0; i < A1.A.Length; i++)
        if (A1.A[i] != A2.A[i])
          return false;

      return true;
    }

    // Метод, що перевантажує оператор !=
    public static bool operator!=(ArrayRange A1, ArrayRange A2)
    {
      return !(A1 == A2);
    }
  }

  internal class Program
  {
    static void Main(string[] args)
    {
      // 1. Створити масиви типу int[]
      int[] AI1 = { 2, 8, 1, -3, 4 };
      int[] AI2 = { 2, 8, 1, -3, 4 };

      // 2. Створити масиви типу ArrayRange
      ArrayRange A1 = new ArrayRange(AI1, 1, 5);
      ArrayRange A2 = new ArrayRange(AI2, 1, 5);

      // 3. Вивести масиви
      A1.Print("A1");
      A2.Print("A2");

      // 4. Викликати перевантажений оператор порівняння масивів ==
      if (A1 == A2)
        Console.WriteLine("A1 == A2");
      else
        Console.WriteLine("A1 != A2");

      // 5. Викликати другий перевантажений оператор !=
      if (A1 != A2)
        Console.WriteLine("A1 != A2");
      else
        Console.WriteLine("A1 == A2");

      Console.ReadKey();
    }
  }
}

Результат

A1
2 5 1 1 4
-----------------------------
A2
2 5 1 1 4
-----------------------------
A1 == A2
A1 == A2

 

2. Перевантаження бінарних операторів порівняння <, >, <=, >=. Приклад

Перевантаження бінарних операторів порівняння >, <, >=, <= повинно бути реалізоване парами. Це означає, що обов’язково потрібно реалізовувати наступні пари операторів:

  • > та <;
  • >= та <=.

На прикладі класу Line демонструється перевантаження бінарних операторів порівняння >, <, >=, <=. Методи класу

operator<()
operator>()
operator>=()
operator<=()

повертають результат порівняння довжин відрізків, що є вхідними параметрами.

using System;

namespace ConsoleApp6
{
  // Клас, що описує лінію, яка складається з двох точок
  class Line
  {
    // Внутрішні змінні - координати відрізка
    private double x1, y1, x2, y2;

    // Конструктор
    public Line(double x1, double y1, double x2, double y2)
    {
      this.x1 = x1;
      this.y1 = y1;
      this.x2 = x2;
      this.y2 = y2;
    }

    // Властивості доступу
    public double X1 { get { return x1; } }
    public double Y1 { get { return y1; } }
    public double X2 { get { return x2; } }
    public double Y2 { get { return y2; } }

    // Метод, що виводить координати лінії
    public void Print(string msg)
    {
      Console.Write(msg + "=> ( " + x1 + "; " + y1 + ") - ( " + x2 + "; " + y2 + "), ");
      Console.WriteLine(" length = {0:f2}", Length());
    }

    // Метод, що повертає довжину відрізка
    public double Length()
    {
      return Math.Sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
    }

    // Перевантажені методи <, >, <=, >=.
    // У методах порівнюються довжини відрізків ln1 та ln2
    public static bool operator>(Line ln1, Line ln2)
    {
      return ln1.Length() > ln2.Length();
    }

    public static bool operator<(Line ln1, Line ln2)
    {
      return !(ln1 > ln2);
    }

    public static bool operator>=(Line ln1, Line ln2)
    {
      return ln1.Length() >= ln2.Length();
    }

    public static bool operator <=(Line ln1, Line ln2)
    {
      return ln1.Length() <= ln2.Length();
    }
  }

  internal class Program
  {
    static void Main(string[] args)
    {
      // 1. Оголосити 2 відрізки
      Line ln1 = new Line(1, 1, 2, 4);
      Line ln2 = new Line(3, 5, -1, -7);

      // 2. Вивести інформацію про відрізки ln1, ln2
      ln1.Print("ln1");
      ln2.Print("ln2");

      // 3. Порівняти ln1 < ln2
      if (ln1 < ln2)
        Console.WriteLine("ln1 < ln2");
      else
        Console.WriteLine("ln1 >= ln2");

      // 4. Порівняти ln1 > ln2
      if (ln1 > ln2)
        Console.WriteLine("ln1 > ln2");
      else
        Console.WriteLine("ln1 <= ln2");

      // 5. Порівняти ln1 <= ln2
      if (ln1 <= ln2)
        Console.WriteLine("ln1 <= ln2");
      else
        Console.WriteLine("ln1 > ln2");

      // 6. Порівняти ln1 >= ln2
      if (ln1 >= ln2)
        Console.WriteLine("ln1 >= ln2");
      else
        Console.WriteLine("ln1 < ln2");

      Console.ReadKey();
    }
  }
}

Результат

ln1=> ( 1; 1) - ( 2; 4), length = 3.16
ln2=> ( 3; 5) - ( -1; -7), length = 12.65
ln1 < ln2
ln1 <= ln2
ln1 <= ln2
ln1 < ln2

 

3. Перевантаження бітових бінарних операторів & (логічне побітове “І”), | (логічне побітове “АБО”), ^ (додавання по модулю 2)

У прикладі демонструється поелементне оперування масивами, які складаються з 0 та 1. Задано клас ArrayBits, в якому оголошується масив типу byte[]. Елементи масиву складаються зі значень 0 та 1. У класі перевантажуються логічні побітові оператори &, |, ^.

Методи, що перевантажують оператори реалізують відповідні операції над кожним елементом масиву. Операторний метод operator&() виконує побітове логічне “І” над елементами двох масивів. Операторний метод operator|() виконує побітове логічне “АБО” над елементами масивів. Відповідно метод operator^() виконує побітове логічне додавання над кожним з елементів масиву.

Демонстраційний програмний код консольного додатку наступний.

using System;

namespace ConsoleApp6
{
  // Клас, що описує масив бітів 0, 1
  class ArrayBits
  {
    private byte[] AB;

    // Конструктор
    public ArrayBits(byte[] _AB)
    {
      // Створити новий масив, в якому ненульові значення рівні 1,
      // а нульові значення рівні 0
      AB = new byte[_AB.Length];

      for (int i = 0; i < _AB.Length; i++)
        if (_AB[i] != 0)
          AB[i] = 1;
        else
          AB[i] = 0;
    }

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

    // Перевантаження операторів &, |, ^
    // Побітове "І"
    public static ArrayBits operator&(ArrayBits AB1, ArrayBits AB2)
    {
      ArrayBits res;

      // Вибрати масив з найменшою довжиною
      // і на основі нього створити результуючий масив
      if (AB1.AB.Length<AB2.AB.Length)
      {
        res = new ArrayBits(AB1.AB);
      }
      else
      {
        res = new ArrayBits(AB2.AB);
      }

      // Реалізувати поелементне побітове "І",
      // сформувати масив res
      for (int i = 0; i < res.AB.Length; i++)
        if ((AB1.AB[i] == 1) && (AB2.AB[i] == 1))
          res.AB[i] = 1;
        else
          res.AB[i] = 0;

      // Повернути результуючий масив
      return res;
    }

    // Побітове "АБО"
    public static ArrayBits operator|(ArrayBits AB1, ArrayBits AB2)
    {
      ArrayBits res;

      // Вибрати масив з найменшою довжиною
      // і на основі нього створити результуючий масив
      if (AB1.AB.Length < AB2.AB.Length)
      {
        res = new ArrayBits(AB1.AB);
      }
      else
      {
        res = new ArrayBits(AB2.AB);
      }

      // Реалізувати поелементне побітове "АБО",
      // сформувати масив res
      for (int i = 0; i < res.AB.Length; i++)
        if ((AB1.AB[i] == 0) && (AB2.AB[i] == 0))
          res.AB[i] = 0;
        else
          res.AB[i] = 1;

      // Повернути результуючий масив
      return res;
    }

    // Побітове додавання по модулю 2
    public static ArrayBits operator^(ArrayBits AB1, ArrayBits AB2)
    {
      ArrayBits res;

      // Вибрати масив з найменшою довжиною
      // і на основі нього створити результуючий масив
      if (AB1.AB.Length < AB2.AB.Length)
      {
        res = new ArrayBits(AB1.AB);
      }
      else
      {
        res = new ArrayBits(AB2.AB);
      }

      // Реалізувати поелементне побітове додавання по модулю 2,
      // сформувати масив res
      for (int i = 0; i < res.AB.Length; i++)
        if (AB1.AB[i] == AB2.AB[i])
          res.AB[i] = 0;
        else
          res.AB[i] = 1;

      // Повернути результуючий масив
      return res;
    }
  }

  internal class Program
  {
    static void Main(string[] args)
    {
      // 1. Створити 2 тестувальні масиви типу byte[]
      byte[] A1 = { 2, 3, 0, 0, 4, 7, 0, 55 };
      byte[] A2 = { 1, 0, 6, 0, 2, 0, 8, 9, 4, 0, 0 };

      // 2. Створити 2 об'єкти на основі масивів A1 та A2
      ArrayBits AB1 = new ArrayBits(A1);
      ArrayBits AB2 = new ArrayBits(A2);

      // 3. Вивести масиви в екземплярах для контролю
      AB1.Print("AB1 ");
      AB2.Print("AB2 ");

      // 4. Реалізувати побітове & - І
      ArrayBits AB3;
      AB3 = AB1 & AB2; // => ArrayBits.operator&(AB1, AB2);
      AB3.Print("AB1 & AB2");

      // 5. Вивести результат побітового | - АБО
      (AB1 | AB2).Print("AB1 | AB2"); // => ArrayBits.operator|(AB1, AB2);

      // 6. Реалізувати побітове ^ - додавання по модулю 2
      ArrayBits AB4 = AB1 ^ AB2; // => ArrayBits.operator^(AB1, AB2);
      AB4.Print("AB1 ^ AB2");

      Console.ReadKey();
    }
  }
}

Результат

AB1 => 1 1 0 0 1 1 0 1
AB2 => 1 0 1 0 1 0 1 1 1 0 0
AB1 & AB2 => 1 0 0 0 1 0 0 1
AB1 | AB2 => 1 1 1 0 1 1 1 1
AB1 ^ AB2 => 0 1 1 0 0 1 1 0

 

4. Перевантаження операторів зсуву <<, >>. Приклад

У класі оператори зсуву перевантажуються в парі. Це означає, що якщо перевантажується оператор << (зсув вліво), то також потрібно перевантажувати оператор >> (зсув вправо).

using System;

namespace ConsoleApp6
{
  // Масив цілих чисел
  class ArrayInt
  {
    private int[] AI;

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

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

    // Перевантаження оператора зсуву вліво <<
    // Елементи масиву зсуваються циклічно вліво,
    // перший елемент масиву стає на місце останнього.
    // Звернути увагу: метод отримує екземпляр типу ArrayInt та ціле число int
    public static ArrayInt operator<<(ArrayInt AI, int n)
    {
      // 1. Створити екземпляр масиву AI
      ArrayInt res = new ArrayInt(AI.AI);

      for (int k = 0; k < n; k++)
      {
        // Циклічний зсув на одну позицію вліво
        int t = res.AI[0];
        for (int i = 0; i < res.AI.Length - 1; i++)
          res.AI[i] = res.AI[i + 1];
        res.AI[AI.AI.Length - 1] = t;
      }

      // 2. Результуючий екземпляр
      return res;
    }

    // Операторний метод, що перевантажує оператор >> зсуву вправо
    public static ArrayInt operator >>(ArrayInt AI, int n)
    {
      // 1. Створити екземпляр масиву AI
      ArrayInt res = new ArrayInt(AI.AI);

      for (int k = 0; k < n; k++)
      {
        // Циклічний зсув на одну позицію вліво
        int t = res.AI[AI.AI.Length - 1];
        for (int i = res.AI.Length - 1; i >= 1; i--)
          res.AI[i] = res.AI[i - 1];
        res.AI[0] = t;
      }

      // 2. Результуючий екземпляр
      return res;
    }
  }

  internal class Program
  {
    static void Main(string[] args)
    {
      // 1. Оголосити масив типу int[]
      int[] A = { 2, 8, 9, 15, 27 };

      // 2. Створити екземпляр типу ArrayInt
      ArrayInt AI = new ArrayInt(A);
      AI.Print("AI "); // Вивести масив

      // 3. Викликати оператор зсуву вліво на 2 позиції
      ArrayInt res = AI << 2;
      res.Print("AI << 2");

      // 4. Викликати оператор зсуву вправо на 4 позиції
      res = AI >> 4;
      res.Print("AI >> 4");

      Console.ReadKey();
    }
  }
}

Результат

AI => 2 8 9 15 27
AI << 2 => 9 15 27 2 8
AI >> 4 => 8 9 15 27 2

 


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