Перевантаження інкрементних та декрементних операторів ++, – –. Приклади
Зміст
- 1. Особливості перевантаження інкрементних та декрементних операторів ++, – –
- 2. Як в операторах інкременту ++ та декременту – – відрізнити реалізації операторних функцій в класі для префіксної та постфіксної форм?
- 3. Приклад перевантаження операторних функцій ++ та – – в класі для одиночних об’єктів
- 4. Приклад перевантаження операторних функцій ++ та – – в класі, які обробляють масиви
- 5. Особливості перевантаження операторів інкременту та декременту з допомогою дружніх функцій
- 6. Відмінності в перевантаженні префіксних та постфіксних операторів інкременту (++) та декременту (– –) з допомогою “дружніх” функцій
- 7. Приклади операторних функцій, які перевантажують оператори інкременту та декременту, і які реалізовані як “дружні функції”
- Зв’язані теми
Пошук на інших ресурсах:
1. Особливості перевантаження інкрементних та декрементних операторів ++, —
Інкрементні та декрементні оператори в мові C++ можуть бути перевантажені. Особливість перевантаження цих операторів полягає в тому, що потрібно перевантажувати як префіксну так і постфіксну форму цих операторів.
Як відомо, у мові C++ операції ++ та – – мають префіксну і постфіксну форми, як показано у прикладі:
++x; // префіксна форма оператора інкременту x++; // постфіксна форма оператора --x; // префіксна форма оператора декременту x--; // постфіксна форма оператора декременту
Згідно синтаксису C++ оператори ++ та — потребують одного операнда.
⇑
2. Як в операторах інкременту ++ та декременту — відрізнити реалізації операторних функцій в класі для префіксної та постфіксної форм?
Згідно синтаксису C++ оператори декременту та інкременту потребують одного операнда. Виникає питання: як реалізувати префіксну та постфіксну перевантажену операторну функцію так, щоб вони відрізнялись (не було співпадіння)?
Для того, щоб при реалізації в класі, відрізнити префіксну та постфіксну форми реалізації операторної функції ++ або —, потрібно дотримуватись наступних правил:
- якщо перевантажується префіксна форма оператора ++, то в класі потрібно реалізувати операторну функцію operator++() без параметрів;
- якщо перевантажується префіксна форма оператора – –, то в класі потрібно реалізувати операторну функцію operator- -() без параметрів;
- якщо перевантажується постфіксна форма оператора ++, то в класі потрібно реалізувати операторну функцію operator++(int d) з одним цілочисельним параметром. У цьому випадку параметр d не використовується у функції. Він вказується тільки для того, щоб вказати що це саме постфіксна реалізація оператора ++. Ім’я d може бути замінене іншим іменем;
- якщо перевантажується постфіксна форма оператора – –, то в класі потрібно реалізувати операторну функцію operator–(int d) з одним цілочисельним параметром. Параметр d необхідний для вказання того, що перевантажується постфіксна реалізація оператора – –.
Наприклад.
class SomeClass { // ... // операторна функція, яка переванажує префіксний оператор ++ (++X) type operator++() { // тіло операторної функції // ... } // операторна функція, яка переванажує постфіксний оператор ++ (X++) type operator++(int d) { // тіло операторної функції // ... } // операторна функція, яка переванажує префіксний оператор -- (--X) type operator--() { // тіло операторної функції // ... } // операторна функція, яка переванажує постфіксний оператор -- (X--) type operator--(int d) { // тіло операторної функції // ... } };
⇑
3. Приклад перевантаження операторних функцій ++ та – – в класі для одиночних об’єктів
Демонстрється реалізація операторних функцій для класу Integer, який реалізує цлочисельне значення.
Оголошується клас Integer, який містить:
- внутрішню змінну number цілого типу. Ця змінна зберігає цілочисельне значення;
- два конструктори, які ініціалізують змінну number;
- методи доступу до змінної number Get(), Set();
- дві операторні функції, які перевантажують оператор ++;
- дві операторні функції, що перевантажують оператор – –.
Реалізація класу Integer наступна:
// перевантаження інкрементних операторів для класу Integer class Integer { private: int number; // член даних public: // конструктори класу // конструктор без параметрів Integer() { number = 0; } // конструктор з 1 параметром Integer(int _number) { number = _number; } // методи доступу void Set(int _number) { number = _number; } int Get(void) { return number; } // операторна функція, яка перевантажує // префіксну форму оператора ++ для класу Integer Integer operator++(void) { number++; return *this; // повернути об'єкт даного класу } // операторна функція, яка перевантажує // постфіксну форму оператора ++ для класу Integer Integer operator++(int d) // параметр d не використовується { number++; return *this; } // перевантаження префіксного -- Integer operator--(void) { number--; return *this; } // перевантаження постфіксного -- Integer operator--(int d) // параметр d не використовується { number--; return *this; } };
Нижче наведено використання класу Integer
// демонстрація використання перевантажених інкрементних // операторних функцій Integer d1, d2(5); // оголошення об'єктів класу Integer Integer d3; int t1, t2; // перевірка t1 = d1.Get(); // t1 = 0 t2 = d2.Get(); // t2 = 5 // виклик перевантажених операторних функцій ++d1; // виклик префіксної операторної функції operator++() t1 = d1.Get(); // t1 = 1 d2++; // виклик постфіксної операторної функції operator++(int) t2 = d2.Get(); // t2 = 6 --d1; // префіксний -- d1--; // постфіксний -- t1 = d1.Get(); // t1 = -1
⇑
4. Приклад перевантаження операторних функцій ++ та – – в класі, які обробляють масиви
Оголошується клас ArrayInt, в якому продемонстровано перевантаження префіксних та постфіксних операторних функцій operator++() та operator- -(), які відповідно збільшують та зменшують на 5 кожен елемент масиву.
Оголошення класу ArrayInt має вигляд:
// клас, що реалізує масив цілих чисел class ArrayInt { private: int A[100]; // внутрішня змінна - масив цілих чисел int size; // кількість елементів масиву public: // конструктори ArrayInt() { size = 0; } ArrayInt(int _size) { if (_size>100) _size=100; size = _size; for (int i=0; i<size; i++) A[i] = 0; } // методи доступу void SetAi(int index, int value) { if ((index>=0) && (index<=size)) A[index] = value; } int GetAi(int index) { return A[index]; } int GetSize(void) { return size; } // перевантажений оператор ++ // префіксна форма ArrayInt operator++(void) { for (int i=0; i<size; i++) A[i] = A[i] + 5; return *this; } // постфіксна форма оператора ++, параметр t не використовується ArrayInt operator++(int t) { for (int i=0; i<size; i++) A[i] = A[i] + 5; return *this; } // префіксна форма оператора -- ArrayInt operator--(void) { for (int i=0; i<size; i++) A[i] = A[i] - 5; return *this; } // постфіксна форма оператора --, параметр t не використовується ArrayInt operator--(int t) { for (int i=0; i<size; i++) A[i] = A[i] - 5; return *this; } };
Використання класу ArrayInt може бути таким
// демонстрація використання перевантажених інкрементних // операторних функцій ArrayInt AA(10); int t; // ініціалізація масиву AA деякими значеннями for (int i=0; i<AA.GetSize(); i++) AA.SetAi(i, i+1); // перевірка t = AA.GetAi(2); // t = 3 // виклик перевантажених операторних функцій AA++; t = AA.GetAi(2); // t = 3+5 = 8 --AA; AA--; t = AA.GetAi(2); // t = 8-5-5 = -2
⇑
5. Особливості перевантаження операторів інкременту та декременту з допомогою дружніх функцій
Якщо оператори ++ та — перевантажуються з допомого дружніх функцій до класу, то потрібно враховувати наступне:
- дружня до класу функція не отримує покажчика this класу;
- оскільки дружня функція не отримує покажчика this, то параметр у цю функцію має передаватись за посиланням а не за значенням. Це означає, що перед іменем параметру вказується символ посилання &.
⇑
6. Відмінності в перевантаженні префіксних та постфіксних операторів інкременту (++) та декременту (—) з допомогою “дружніх” функцій
Для того, щоб при реалізації дружньої функції до класу, відрізнити префіксну та постфіксну форми реалізації операторної функції ++ або —, потрібно дотримуватись наступних правил:
- якщо перевантажується префіксна форма оператора ++ (++x), то “дружня” операторна функція повинна отримувати один параметр. Цей параметр є посиланням на клас, для якого ця функція реалізована;
- якщо перевантажується префіксна форма оператора – – (– –x), то “дружня” операторна функція повинна отримувати один параметр, який є посиланням на клас в якому ця функція реалізована;
- якщо перевантажується постфіксна форма оператора ++ (x++), то “дружня” операторна функція отримує два параметри. Перший параметр є посиланням на дружній клас. Другий параметр є формальним параметром цілого типу, який служить індикатором того, що перевантажується саме постфіксна а не префіксна форма оператора ++. Другий параметр у функції не використовується;
- якщо перевантажується постфіксна форма оператора – – (x– –), то дружня операторна функція отримує два параметри. Перший параметр є посиланням на дружній клас. Другий параметр не використовується, а служить для визначення того, що саме постфіксна форма оператора – – реалізована.
Наприклад.
// оголошення деякого класу class SomeClass { // тіло класу // ... // оголошення дружніх функцій для класу SomeClass friend SomeClass operator++(SomeClass & ref); // ++x friend SomeClass operator--(SomeClass & ref); // --x friend SomeClass operator++(SomeClass & ref, int d); // x++ friend SomeClass operator--(SomeClass & ref, int d); // x-- }; // оголошення операторної функції, // яка перевантажує префіксний оператор ++ (++x) SomeClass operator++(SomeClass & ref) { // ... } // оголошення операторної функції, // яка перевантажує префіксний оператор -- (--x) SomeClass operator++(SomeClass & ref) { // ... } // оголошення операторної функції, // яка перевантажує постфіксний оператор ++ (x++) SomeClass operator++(SomeClass & ref, int d) { // ... } // оголошення операторної функції, // яка перевантажує постфіксний оператор -- (x--) SomeClass operator++(SomeClass & ref, int d) { // ... }
Як видно з прикладу, “дружня” операторна функція отримує посилання на “дружній” клас.
⇑
7. Приклади операторних функцій, які перевантажують оператори інкременту та декременту, і які реалізовані як “дружні функції”
Приклад 1. Перевантажуються оператори ++ та – – для класу Integer з допомогою “дружніх” операторних функцій. “Дружні” операторні функції реалізуються за межами класу.
// клас Integer, що реалізує ціле число class Integer { private: int number; public: // конструктори класу Integer() { number = 0; } Integer(int _number) { number = _number; } // методи доступу int Get(void) { return number; } void Set(int _number) { number = _number; } // оголошення "дружніх" операторних функцій friend Integer operator++(Integer & ref); friend Integer operator--(Integer & ref); friend Integer operator++(Integer & ref, int d); friend Integer operator--(Integer & ref, int d); }; // реалізація "дружніх" операторних функцій Integer operator++(Integer & ref) { ref.number++; // доступ за посиланням return ref; } Integer operator--(Integer & ref) { ref.number--; return ref; } // постфіксна форма - x++ Integer operator++(Integer & ref, int d) { ref.number++; return ref; } // постфіксна форма - x-- Integer operator--(Integer & ref, int d) { ref.number--; return ref; }
Використання класу Integer в іншому методі може бути, наприклад, таким:
// "дружні" операторні функції, перевантаження операторів ++, -- Integer d1, d2(8); int t; // перевірка t = d1.Get(); // t = 0 t = d2.Get(); // t = 8 // виклик "дружніх" операторних функцій ++d1; // "дружня" префіксна операторна функція operator++() d2--; // "дружня" постфіксна операторна функція operator--() t = d1.Get(); // t = 1 t = d2.Get(); // t = 7
Приклад 2. Перевантажуються оператори ++ та — для класу ArrayInt з допомогою “дружніх” операторних функцій. У класі ArrayInt оголошуються внутрішні дані, конструктори, методи доступу та “дружні” до класу операторні функції.
“Дружні” операторні функції перевантажують оператори ++ та – –. “Дружні” операторні функції збільшують або зменшують на 1 значення кожного елементу масиву, який оголошений в класі ArrayInt.
Реалізація класу ArrayInt та “дружніх” операторних функцій наступна
// клас ArrayInt, який реалізує масив цілих чисел class ArrayInt { private: int *A; // масив цілих чисел, розмір масиву довільний int size; // розмір масиву public: // конструктори класу ArrayInt() { size = 0; A = NULL; } // конструктор з 1 параметром ArrayInt(int _size) { size = _size; A = new int[size]; for (int i=0; i<size; i++) A[i] = 0; } // методи доступу int GetSize(void) { return size; } void SetSize(int _size) { // звільнити попередній фрагмент пам'яті if (size>0) delete[] A; // встановити новий розмір масиву size = _size; A = new int[size]; for (int i=0; i<size; i++) A[i] = 0; } int GetAi(int index) { return A[index]; } void SetAi(int index, int value) { A[index] = value; } // "дружні" операторні функції ++, -- friend ArrayInt operator++(ArrayInt & AI); friend ArrayInt operator--(ArrayInt & AI); friend ArrayInt operator++(ArrayInt & AI, int d); friend ArrayInt operator--(ArrayInt & AI, int d); }; // реалізація "дружніх" операторних функцій ++, -- // ++x ArrayInt operator++(ArrayInt & AI) { // збільшити кожен елемент масиву на 1 for (int i=0; i<AI.size; i++) AI.A[i] = AI.A[i] + 1; // доступ за посиланням return AI; } // --x ArrayInt operator--(ArrayInt & AI) { // зменшити кожен елемент масиву на 1 for (int i=0; i<AI.size; i++) AI.A[i] = AI.A[i] - 1; // доступ за посиланням return AI; } // x++ ArrayInt operator++(ArrayInt & AI, int d) { // збільшити кожен елемент масиву на 1 for (int i=0; i<AI.size; i++) AI.A[i] = AI.A[i] + 1; // доступ за посиланням return AI; } // x-- ArrayInt operator--(ArrayInt & AI, int d) { // зменшити кожен елемент масиву на 1 for (int i=0; i<AI.size; i++) AI.A[i] = AI.A[i] - 1; // доступ за посиланням return AI; }
Нижче продемонстровано використання класу ArrayInt та операторних функцій
// "дружні" операторні функції, перевантаження операторів ++, -- ArrayInt A(10); int t; // встановлення довільних значень в масиві for (int i=0; i<A.GetSize(); i++) A.SetAi(i, i+1); // A.A[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 } // перевірка t = A.GetAi(3); // t = 4 t = A.GetAi(5); // t = 6 // використання перевантажених операторів ++, -- A++; // постфіксна функція operator++(ArrayInt, int) t = A.GetAi(3); // t = 5 t = A.GetAi(5); // t = 7 --A; --A; t = A.GetAi(3); // t = 3 t = A.GetAi(5); // t = 5 ++A; ++A; ++A; t = A.GetAi(3); // t = 6
⇑
Зв’язані теми
- Перевантаження операторів у C++. Операторна функція. Ключове слово operator. Перевантаження арифметичних операторів +, –, *, /. Приклади реалізації вбудованих операторних функцій
- “Дружні” операторні функції: відмінності, реалізація особливості застосування. Перевантаженняоператорів +, –, *, / з допомогою “дружніх” операторних функцій