Перегрузка инкрементных и декрементных операторов ++, ––. Примеры
Содержание
- 1. Особенности перегрузки инкрементных и декрементных операторов ++, ––
- 2. Как в операторах инкремента ++ и декремента –– отличить реализации операторных функций в классе для префиксной и постфиксной форм?
- 3. Пример перегрузки операторных функций ++ и –– в классе для одиночных объектов
- 4. Пример перегрузки операторных функций ++ и –– в классах, которые обрабатывают массивы
- 5. Особенности перегрузки операторов инкремента (++) и декремента (––) с помощью дружественных функций
- 6. Отличия в перегрузке префиксных и постфиксных операторов инкремента (++) и декремента (––) с помощью «дружественных» функций
- 7. Примеры операторных функций, которые перегружают операторы инкремента и декремента, и которые реализованы как «дружественные функции»
- Связанные темы
Поиск на других ресурсах:
1. Особенности перегрузки инкрементных и декрементных операторов ++, ––
Инкрементные и декрементные операторы в языке C++ могут быть перегружены. Особенность перегрузки этих операторов состоит в том, что нужно перегружать как префиксную так и постфиксную форму этих операторов.
Как известно, в языке C++ операции ++ и –– имеют префиксную и постфиксную формы, как показано в примере:
++x; // префиксная форма оператора инкремента x++; // постфиксная форма оператора инкремента --x; // префиксная форма оператора декремента x--; // постфиксная форма оператора декремента
⇑
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++), то «дружественная» операторная функция получает два параметра. Первый параметр есть ссылкой на дружественный класс. Второй параметр есть формальным параметром целого типа, который служит индикатором того, что перегружается именно постфиксная а не префиксная форма оператора ++. Второй параметр в функции не используется;
- если перегружается постфиксная форма оператора —, то дружественная операторная функция получает два параметра. Первый параметр есть ссылкой на дружественный класс. Второй параметр не используется, а служит для определения того, что именно постфиксная форма оператора — реализована.
Например.
// объявление некоторого класса 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. Перегрузка базовых арифметических операторов +, –, *, /. Примеры реализации встроенных операторных функций
- «Дружественные» операторные функции: отличия, реализации, особенности применения. Перегрузка операторов +, –, *, / с помощью «дружественных» операторных функций
⇑