Перевантаження операторів -> та ‘ , ‘ (кома). Приклади
Зміст
- 1. Особливості перевантаження оператора посилання на член об’єкта ->. Загальна форма. Операторна функція operator->()
- 2. Приклад перевантаження оператору -> в класі, що містить одиночну внутрішню змінну типу double
- 3. Приклад перевантаження оператору -> для класу, що містить динамічний масив екземплярів класу
- 4. Особливості перевантаження оператора ‘ , ‘ (кома). Операторна функція operator,()
- 5. Приклад перевантаження оператора ‘ , ‘
- Зв’язані теми
Пошук на інших ресурсах:
1. Особливості перевантаження оператора посилання на член об’єкта ->. Загальна форма. Операторна функція operator->()
У C++ оператор доступу до члена об’єкта -> можна перевантажувати. Якщо оператор -> перевантажений, то виклик елемента класу має такий загальний вигляд
obj->item
де
- obj – об’єкт класу;
- item – деякий елемент класу (внутрішня змінна, метод). Цей елемент повинен бути членом класу, який є доступний всередині об’єкту.
При перевантаженні слід враховувати наступні особливості:
- оператор -> вважається унарним;
- операторна функція operator->() повинна повертати покажчик на об’єкт класу, для якого він визначений;
- операторна функція operator->() повинна бути членом класу, для якого вона реалізується.
Загальна форма класу, в якому перевантажений оператор ->, наступна
class ClassName { // ... // операторна функція ClassName* operator->() { // тіло операторної функції // ... return this; // повернути покажчик на об'єкт класу } };
⇑
2. Приклад перевантаження оператору -> в класі, що містить одиночну внутрішню змінну типу double
Оголошується клас Double, що містить внутрішню змінну d типу double. У класі реалізована перевантажена функція operator->(), яка перевантажує оператор ->.
#include <iostream> using namespace std; class Double { public: double d; // внутрішня змінна // операторна функція, що перевантажує // оператор -> Double* operator->() { return this; // повернути покажчик на клас } }; void main() { // перевантаження оператора доступу за покажчиком -> Double D; // екземпляр класу D double x; D.d = 3.85; // виклик операторної функції operator->() x = D->d; // інший спосіб доступу x = D.d; // x = 3.85 cout << "x = " << x; }
Результат виконання програми
x = 3.85
⇑
3. Приклад перевантаження оператору -> для класу, що містить динамічний масив екземплярів класу
У прикладі демонструється перевантаження оператору -> для класу, в якому реалізовано динамічний масив об’єктів (екземплярів) класу.
Задано клас Point, що описує точку на площині. У класі Point реалізовано такі елементи:
- внутрішні змінні x, y – координати точки;
- конструктори;
- методи доступу GetX(), GetY(), SetXY().
Також задано клас Polygon, що реалізує масив точок. У класі оголошуються:
- внутрішня прихована (private) змінна-покажчик на тип Point. Ця змінна містить покажчик на динамічний масив точок типу Point;
- внутрішня прихована (private) змінна n, що визначає кількість елементів масиву;
- конструктор;
- метод GetN(), який призначений для отримання значення n;
- метод Add(), який додає нову точку типу Point до масиву. Нова точка отримується як параметр методу;
- метод Delete(), який видаляє точку з заданої позиції index.
Позиція index є вхідним параметром методу;
- метод GetPoint(), який повертає значення точки типу Point в заданій позиції index;
- метод Show(), що відображає на екрані значення масиву точок в класі Polygon;
- операторна функція operator->(), яка перевантажує оператор ->.
Текст програми типу Console Application, що містить реалізації класів Point та Polygon, наступний
#include <iostream> using namespace std; // клас, що описує точку class Point { private: double x, y; // внутрішні змінні public: // конструктори класу Point() { x = y = 0; } Point(double x, double y) { this->x = x; this->y = y; } // методи доступу void SetXY(double x, double y) { this->x = x; this->y = y; } double GetX(void) { return x; } double GetY(void) { return y; } }; // клас багатокутник class Polygon { private: Point * Pt; // масив точок int n; // кількість точок public: // конструктор Polygon() { n = 0; Pt = NULL; } // методи доступу // зчитати кількість точок int GetN(void) { return n; } // додати нову точку void Add(Point p) { Point * Pt2; // виділити пам'ять на новий масив типу Point - на 1 елемент більше Pt2 = new Point[n + 1]; // скопіювати Pt=>Pt2 for (int i = 0; i < n;i++) Pt2[i].SetXY(Pt[i].GetX(), Pt[i].GetY()); // додати зайвий елемент Pt2[n].SetXY(p.GetX(), p.GetY()); // знищити пам'ять, виділену під старий масив if (n > 0) delete[] Pt; // присвоїти внутрішній змінній новий масив Pt = Pt2; n++; } // видалити точку в позиції pos void Delete(int pos) { if (n < 0) return; if (pos > (n - 1)) return; if (pos < 0) return; // якщо один елемент, то видалити його if (n == 1) { n = 0; delete[] Pt; return; } // n>1 Point* Pt2; // новий масив double tx, ty; // додаткові змінні Pt2 = new Point[n - 1]; // виділити пам'ять під новий масив - на 1 елемент менше // скопіювати Pt в Pt2 в обхід позиції pos // до позиції pos for (int i = 0; i < pos; i++) { tx = Pt[i].GetX(); ty = Pt[i].GetY(); Pt2[i].SetXY(tx, ty); } // після позиції pos for (int i = pos + 1; i < n; i++) { tx = Pt[i].GetX(); ty = Pt[i].GetY(); Pt2[i-1].SetXY(tx, ty); // Pt2[i-1] - важливо } // звільнити пам'ять, виділену для Pt раніше delete[] Pt; // зменшити к-сть елементів на 1 n--; // встановити нове значення Pt // перенаправити Pt на Pt2 Pt = Pt2; } // взяти точку з позиції index Point GetPoint(int index) { if ((index >= 0) && (index < n)) return Point(Pt[index].GetX(), Pt[index].GetY()); else return Point(0.0, 0.0); } // метод, що виводить масив void Show(void) { double x, y; int i; for (i = 0; i < n; i++) { x = Pt[i].GetX(); y = Pt[i].GetY(); cout << "x" << i + 1 << " = " << x << ", "; cout << "y" << i + 1 << " = " << y; cout << endl; } } // операторна функція, що перевантажує оператор -> Polygon* operator->() { return this; } }; void main() { // перевантаження оператора доступу за покажчиком -> Polygon Pol; // екземпляр класу Polygon double x, y; int i; Point Pt; // сформувати довільний масив з 5 точок for (i = 0; i < 5; i++) { x = (double)(i * 2); y = (double)(i + 3); Pt.SetXY(x, y); // сформувати точку // виклик операторної функції operator-> Pol->Add(Pt); // додати точку } cout << "Array of points: \n"; // вивести масив через звертання до операторної функції operator->() Pol->Show(); // видалити точку в позиції 2 Pol->Delete(2); cout << "Modified array: \n"; cout << "n = " << Pol->GetN() << endl; // знову вивести масив Pol->Show(); }
Результат виконання програми
Array of points: x1 = 0, y1 = 3 x2 = 2, y2 = 4 x3 = 4, y3 = 5 x4 = 6, y4 = 6 x5 = 8, y5 = 7 Modified array: n =4 x1 = 0, y1 = 3 x2 = 2, y2 = 4 x3 = 6, y3 = 6 x4 = 8, y4 = 7
⇑
4. Особливості перевантаження оператора ‘ , ‘ (кома). Операторна функція operator,()
У мові C++ оператор ‘ , ‘ може бути перевантажений. При перевантаженні оператора ‘ , ‘ у класі має бути оголошена операторна функція operator,(). В тіло операторної функції можна помістити будь-який код. Тобто, оператор ‘ , ‘ при бажанні може виконувати будь-які нестандартні операції над об’єктами класу.
У стандартному випадку оператор ‘ , ‘ використовується в операції присвоєння за зразком
obj1 = (obj2, obj3, ..., objN);
де obj1, …, objN – екземпляри деякого класу.
У випадку стандартного використання оператора ‘ , ‘ потрібно врахувати наступні особливості:
- оператор ‘ , ‘ вважається бінарним. Тому операторна функція operator,() отримує один параметр;
- при використанні перевантаженого оператора ‘ , ‘ в операції присвоєння приймається до уваги останній аргумент (цей аргумент є результатом оператора). Усі інші аргументи ігноруються.
В загальному при перевантаженні оператора ‘ , ‘ клас має такий вигляд
class ClassName { // ... // операторна функція, яка перевантажує оператор ',' ClassName operator,(ClassName obj) { // ... } };
де
- ClassName – ім’я класу, в якому перевантажується оператор ‘ , ‘;
- obj – ім’я екземпляру класу, що передається як параметр в операторну функцію operator,().
⇑
5. Приклад перевантаження оператора ‘ , ‘
У прикладі перевантажується оператор ‘,’ в класі Coords3D, що реалізує координати в просторі. У класі оголошуються:
- три внутрішні приховані (private) змінні з іменами x, y, z;
- два конструктори класу;
- метод доступу Get(), призначений для отримання значень x, y, z;
- операторна функція operator,(), яка перевантажує оператор ‘ , ‘.
Вигляд програми для додатку типу Console Application наступний
#include <iostream> using namespace std; // клас, що визначає координати точки в просторі class Coords3D { private: double x, y, z; public: Coords3D() { x = y = z = 0; } Coords3D(double x, double y, double z) { this->x = x; this->y = y; this->z = z; } // метод читання x, y, z void Get(double& x, double& y, double& z) { x = this->x; y = this->y; z = this->z; } // перевантажений оператор , Coords3D operator,(Coords3D obj) { Coords3D tmp; tmp.x = obj.x; tmp.y = obj.y; tmp.z = obj.z; return tmp; } }; void main() { double x, y, z; Coords3D c1(1, 3, 5); // екземпляри класу Coords3D Coords3D c2(2, 4, 6); Coords3D c3; // виклик операторної функції c3.operator,(c2) c3 = (c1, c2); // у c3 записується c2 // перевірка c3.Get(x, y, z); // x = 2, y = 4, z = 6 cout << "x = " << x << endl; cout << "y = " << y << endl; cout << "z = " << z << endl; //------------------------ //створити інший екземпляр Coords3D c4(10, 15, 20); c3 = (c2, c1, c4); // c3 <= c4 // перевірка c3.Get(x, y, z); // x = 10, y = 15, z = 20 cout << endl; cout << "x = " << x << endl; cout << "y = " << y << endl; cout << "z = " << z << endl; }
У вищенаведеному коді в рядку
c3 = (c1, c2);
викликається операторна функція c3.operator,(c2). Отже, до уваги приймається останній екземпляр c2. Екземпляр з іменем c1 ігнорується. Це стосується і рядка
c3 = (c2, c1, c4);
де об’єкту c3 присвоюються значення внутрішніх змінних об’єкта c4.
Висновок: у випадку стандартного використання, при перевантаженні оператора ‘ , ‘ до уваги приймається останній справа аргумент. Усі інші аргументи ігноруються. Однак, слід врахувати, що кожен вираз у послідовності розділеної ‘ , ‘ обчислюється компілятором що необхідно також враховувати.
Результат роботи програми
x = 2 y = 4 z = 6 x = 10 y = 15 z = 20
⇑
Зв’язані теми
- Перевантаження операторів у C++. Операторна функція. Ключове слово operator. Перевантаження арифметичних операторів +, –, *, /. Приклади реалізації вбудованих операторних функцій
- “Дружні” операторні функції: відмінності, реалізація особливості застосування. Перевантаженняоператорів +, –, *, / з допомогою “дружніх” операторних функцій
- Перевантаження оператора індексування елементів масиву [ ]
⇑