Перевантаження операторів. Загальні відомості. Перевантаження унарних операторів –, !, ++, ––
Зміст
- 1. Поняття про перевантаження операторів
- 2. Вимоги та обмеження, що накладаються при перевантаженні операторів
- 3. Перелік операторів, які допускають та не допускають перевантаження
- 4. Загальна форма перевантаження оператора в класі. Ключове слово operator
- 5. Особливості перевантаження унарних операторів
- 6. Приклад перевантаження унарного оператора – (мінус)
- 7. Приклад перевантаження унарного оператора ! (заперечення)
- 8. Приклад перевантаження унарних операторів ++, — (інкремент, декремент)
- 9. Приклад перевантаження унарного оператора ~ (доповнення до 1)
- Споріднені теми
Пошук на інших ресурсах:
1. Поняття про перевантаження операторів
У мові C# існує можливість задавати оператор (+, –, != та інше) для конкретного класу чи структури, який може бути використаний для виконання якихось дій. Як правило, ці дії виконуються над об’єктами цього класу (структури). Представлення дій у вигляді зрозумілих (природніх) операторів покращує сприйняття програмного коду. Таким чином, використання відомих операторів може бути як для базових типів (int, double, char та інших) так і для користувацьких класів (користувацьких типів).
Механізм задавання стандартних операторів для заданого класу чи структури з метою покращення читабельності програм називається перевантаженням операторів. Оператори можна перевантажувати як для класів так і для структур.
Багато стандартних класів реалізують перевантаження багатьох операторів. Наприклад, клас String має перевантажені оператори == та !=, що дає змогу зручно порівнювати два рядки на рівність (нерівність).
⇑
2. Вимоги та обмеження, що накладаються при перевантаженні операторів
При виконанні перевантаження операторів у класах потрібно дотримуватись ряду вимог:
- для реалізації перевантеження потрібно використовувати загальнодоступні статичні методи, які оголошуються в класі;
- в операторному методі забороняється використовувати модифікатори ref або out;
- в операторному методі тип параметру або тип значення, що повертається, повинен співпадати з типом (класом), в якому цей оператор перевантажується.
Також на перевантаження операторів накладаються наступні обмеження:
- перевантаження не змінює пріоритет операторів;
- при перевантаженні оператору кількість операндів, які використовуються, змінити неможливо;
- не всі оператори можна перевантажувати.
⇑
3. Перелік операторів, які допускають та не допускають перевантаження
Не всі оператори допускають перевантаження. У таблиці нижче подано оператори, які можна перевантажувати.
Оператори | Категорія операторів |
– | Зміна знаку на протилежний |
! | Логічне заперечення |
~ | Доповнення до 1 |
++, — | Інкремент, декремент |
true, false | Істинність об’єкту |
+, –, *, /, % | Арифметичні оператори |
&&, || | Логічні оператори |
&, |, ^, <<, >> | Бітові оператори |
==, !=, <, >, <=, >= | Оператори порівняння |
[] | Операція доступу до елементів масиву |
() | Операції перетворення |
Нижче наведено перелік операторів, які не допускають перевантаження.
Оператори | Категорія операторів |
+=, -=, *=, /=, %=, &=, |=, ^=, <<=, >>= | Скорочені оператори присвоєння |
= | Присвоєння |
. | Доступ до елементів |
?: | Тернарний умовний оператор |
new | Створення об’єкту |
as, is, typeof | Отримання інформації про тип |
->, sizeof, *, & | Доступні в небезпечному коді |
⇑
4. Загальна форма перевантаження оператора в класі. Ключове слово operator
Для перевантаження оператора в класі використовується ключове слово operator за наступним синтаксисом
public static return_type operator op(parameters)
тут
- op – оператор, який перевантажується (+, –, != тощо);
- return_type – тип, що повертається при використанні оператора op;
- parameters – список параметрів, які отримує оператор. Для унарних операторів (-, !, ++, –) parameters містить тільки 1 параметр, для бінарних – 2 параметри.
⇑
5. Особливості перевантаження унарних операторів
До унарних операторів, які можна перевантажувати, відносяться оператори:
- – – унарний мінус;
- ! – логічне заперечення;
- ++ – інкремент;
- –– – декремент.
Оскільки, всі перевантажені оператори є статичними методами, то вони не отримують покажчик this поточного екземпляру. Як наслідок, всі операторні методи що перевантажують унарні оператори, отримують один параметр. Цей параметр повинен бути типу класу.
У найбільш загальному випадку перевантаження унарного оператора в класі ClassName виглядає наступним чином
class ClassName { ... public static return_type op(ClassName param) { // Дії, які потрібно виконати // ... } }
тут
- op – позначення одного з унарних операторів –, !, ++, –;
- param – деякий параметр;
- return_type – тип, який повертається. Це може бути будь-який тип, що використовується у програмі.
Після цього, оператор op можна використовувати для класу ClassName приблизно наступним чином
value = op Obj;
тут
- value – значення типу return_type, що отримується;
- Obj – екземпляр класу ClassName.
Наприклад, якщо перевантажено оператор ++, то виклик буде
value = ++Obj;
⇑
6. Приклад перевантаження унарного оператора – (мінус)
У прикладі приводиться перевантаження унарного оператора – (мінус) на прикладі класу, що описує комплексне число. З допомогою перевантаженого оператора знаки дійсної та уявної частини комплексного числа змінюються на протилежні.
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 cm) { return new Complex(-cm.re, -cm.im); } // Метод, що виводить стан поточного екземпляру 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) { // Створити екземпляр класу Complex Complex c1 = new Complex(2.4, -3.8); // Вивести стан екземпляру c1.Print("c1"); // c1 => 2.4-3.8*j // Створити посилання на Complex Complex c2; // Присвоїти посиланню результат повернення // з перевантаженого оператора - c2 = -c1; // викликається метод Complex::operator-(c1); // Вивести стан екземпляру с2 c2.Print("c2"); // c2 => -2.4+3.8*j Console.ReadKey(); } } }
Результат
c1 => 2.4-3.8*j c2 => -2.4+3.8*j
⇑
7. Приклад перевантаження унарного оператора ! (заперечення)
Реалізовано перевантаження унарного оператора ! на прикладі класу, що описує трикутник за його сторонами. Операторний метод повертає значення true, якщо трикутник є рівностороннім з заданою точністю. В іншому випадку повертається false.
У прикладі демонструється тільки мінімальний набір методів з метою демонстрації перевантаження оператора ! (заперечення).
using System; namespace ConsoleApp6 { class Triangle { // Внутрішні поля класу - координати крайніх точок трикутника private double x1, y1, x2, y2, x3, y3; // Конструктор public Triangle(double x1, double y1, double x2, double y2, double x3, double y3) { this.x1 = x1; this.y1 = y1; this.x2 = x2; this.y2 = y2; this.x3 = x3; this.y3 = y3; } // Операторний метод, що перевантажує унарний оператор ! // Метод повертає true, якщо довжини сторін є рівні // з точністю 5 знаків після коми. public static bool operator!(Triangle tr) { // Точність - 5 знаків після коми double eps = 1E-5; // Відстань між точками 1 - 2 double a = Math.Sqrt((tr.x1 - tr.x2) * (tr.x1 - tr.x2) + (tr.y1 - tr.y2) * (tr.y1 - tr.y2)); // Відстань між точками 1 - 3 double b = Math.Sqrt((tr.x1 - tr.x3) * (tr.x1 - tr.x3) + (tr.y1 - tr.y3) * (tr.y1 - tr.y3)); // Відстань між точками 2 - 3 double c = Math.Sqrt((tr.x2 - tr.x3) * (tr.x2 - tr.x3) + (tr.y2 - tr.y3) * (tr.y2 - tr.y3)); return (Math.Abs(a - b) < eps) && (Math.Abs(b - c) < eps) && (Math.Abs(a - c) < eps); } } internal class Program { static void Main(string[] args) { // Створити екземпляр класу Triangle Triangle tr = new Triangle(1, 1, 2, 2, 3, 1); // Викликати перевантажений оператор Triangle::operator!() if (!tr) Console.WriteLine("The sides of the triangle are equal"); else Console.WriteLine("The sides of the triangle are not equal"); Console.ReadKey(); } } }
Результат
The sides of the triangle are not equal
⇑
8. Приклад перевантаження унарних операторів ++, — (інкремент, декремент)
Унарні оператори інкременту (++) та декременту (—) також можуть бути перевантажені. У C# немає відмінності при перевантаженні префіксної чи постфіксної форми операторів інкременту та декременту. Перевантажується префіксна форма, яка має таку саму дію як постфіксна форма.
У прикладі реалізується клас Point, що описує точку на координатній площині. З метою демонстрації, у класі перевантажуються операторні функції
public static Point operator++(Point pt); public static Point operator--(Point pt);
У цих функціях значення координат x, y відповідно збільшуються та зменшуються на 1.
using System; namespace ConsoleApp6 { class Point { // Внутрішні поля - координати точки private double x, y; // Конструктор public Point(double x, double y) { this.x = x; this.y = y; } // Властивості доступу до внутрішніх полів public double X { get { return x; } set { x = value; } } public double Y { get { return y; } set { y = value; } } // Метод, що виводить внутрішній стан класу public void Print(string msg) { Console.WriteLine(msg + " => ( " + x + "; " + y + ")"); } // Методи, що перевантажують оператори інкременту (++) та декременту (--) public static Point operator++(Point pt) { return new Point(pt.x + 1, pt.y + 1); } public static Point operator--(Point pt) { return new Point(pt.x - 1, pt.y - 1); } } internal class Program { static void Main(string[] args) { // 1. Оголосити екземпляр класу Point Point pt1 = new Point(2, 8); // 2. Викликати постфіксну форму оператора інкременту ++ pt1++; // викликається перевантажений оператор ++ для класу Point // 3. Вивести стан екземпляру pt1 pt1.Print("pt1"); // pt1 => ( 3; 9) // 4. Викликати префіксну форму оператора декременту -- --pt1; // 5. Вивести стан екземпляру pt1 повторно pt1.Print("pt1"); // pt1 => ( 2; 8) Console.ReadKey(); } } }
Результат
pt1 => ( 3; 9) pt1 => ( 2; 8)
⇑
9. Приклад перевантаження унарного оператора ~ (доповнення до 1)
У прикладі демонструється перевантаження унарного оператора ~ (тільда).
Оголошується клас Integer, що описує ціле невід’ємне число. У класі оголошується операторний метод
public static Integer operator~(Integer num)
який перевантажує оператор ~. Метод повертає екземпляр класу Integer, в якому число є реверсоване (читається у зворотному порядку).
using System; namespace ConsoleApp6 { // Клас, що описує цілочисельне значення, // яке може бути тільки додатнім і має додаткові властивості class Integer { // Внутрішнє поле - число private int value; // Конструктор public Integer(int value) { if (value < 0) this.value = -value; else this.value = value; } // Властивості доступу public int Value { get { return value; } set { if (value < 0) this.value = -value; else this.value = value; } } // Метод перевантаження оператора ~ // Метод інвертує число. Наприклад, 2351 => 1532 public static Integer operator~(Integer num) { int result = 0; int t; int pow; // Визначити порядок числа t = num.Value / 10; pow = 1; while (t > 0) { t = t / 10; pow *= 10; } // Сформувати результуюче число t = num.Value; while (t>0) { result = result + (t % 10) * pow; t = t / 10; pow = pow / 10; } return new Integer(result); } // Метод, що виводить внутрішнє поле public void Print(string msg) { Console.WriteLine(msg + " => " + value); } } internal class Program { static void Main(string[] args) { // Оголосити екземпляр класу Integer Integer num1 = new Integer(25631); // Вивести значення екземпляру num1.Print("num1"); // Викликати метод, що перевантажує оператор ~ Integer num2 = ~num1; // Вивести результат num2.Print("num2"); Console.ReadKey(); } } }
Результат
num1 => 25631 num2 => 13652
⇑
Споріднені теми
- Перевантаження бінарних операторів. Перевантаження операторів +, –, *, /, %. Вкладення довільної логіки при перевантаженні
- Перевантаження операторів порівняння ==, !=, >, <, >=, <=. Перевантаження логічних побітових операторів &, |, ^
⇑