Перегрузка операторов -> и ‘ , ‘ (запятая). Примеры
Содержание
- 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 Get(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->Get() << 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. Перегрузка базовых арифметических операторов +, –, *, /. Примеры реализации встроенных операторных функций
- «Дружественные» операторные функции: отличия, реализации, особенности применения. Перегрузка операторов +, –, *, / с помощью «дружественных» операторных функций
- Перегрузка оператора индексирования элементов массива [ ]
⇑