БлогNot. C++: общее о перегрузке операторов

C++: общее о перегрузке операторов

Собственно, всё написано у Шилдта, это, скорее, шпаргалка.

Совсем нельзя перегружать: . :: .* ?

Нельзя перегружать не членами класса: = () [] ->

Не надо перегружать, если не какой-то особый случай: new delete -> ->* ,

Если функция перегрузки оператора - член класса, то при перегрузке бинарного оператора неявно (через указатель this) передаётся первый операнд (слева от знака операции), а параметром функции явно передаётся второй операнд (справа от знак операции).

Для унарного оператора операнд передаётся неявно, а явный параметр не нужен.

При переопределении постфискного оператора функции-оператору передаётся дополнительный неиспользуемый параметр типа int, чтобы компилятор мог отличить постфиксную запись от префиксной. При этом реализация постфиксного оператора должна возвращать неизменённый объект.

Если функция перегрузки оператора - не член, но друг (friend) класса, то при перегрузке бинарного оператора явно передаются оба операнда (стоящие слева и справа от знака операции), а при перегрузке унарного оператора явно передаётся ссылка на его единственный операнд. При этом префиксная форма функции-друга принимает один параметр-ссылку (который и является операндом), а постфиксная форма — два параметра (вторым является целочисленное значение, которое не используется).

Перегруженные операторы отношения или логических операцией могут возвращать просто значение типа int или bool.

Вообще говоря, перегрузка бинарной операции, присваивания и унарных постфиксных операторов должны возвращать новый объект класса, созданный внутри операторной функции. Перегрузка унарного префиксного оператора может возвращать как объект класса значение *this. Можно возвращать *this и для перегруженных операций вроде *=, += и т.д. Делать операторные функции с типом возвращаемого значения void не нужно - над объектами не будет работать, например, присваивание по цепочке вида a=b=c.

Для класса с динамически выделяемой под некоторые свойства оперативной памятью нужен явный конструктор копирования, принятое по умолчанию побитовое копирование объектов не подходит (при этом могут быть скопированы адреса динамических объектов, но не их значения). Конструктор копирования должен иметь единственный параметр - const-ссылку на объект класса (копируемый объект; объект, куда копируем, доступен через this).

Корректно переопределённый оператор [] (который может использоваться и слева, и справа от знака "=") должен возвращать ссылку на объект того типа, из которого состоит индексируемая последовательность. В принципе, [] перегружается как бинарный оператор.

Оператор вызова функций () создаёт не новый способ вызова функций, а операторную функцию, которой можно передать произвольное число параметров.

Пример на большую часть сказанного, простейший класс Class состоит только из числа n:

#include <iostream>
#include <cstdlib>

using namespace std;

class Class {
 int n;
public:
 void show(); 
 void show(const char*);
 inline void set(int n) { this->n = n; }
 inline Class(int n = 0) { this->n = n; }
 Class operator + (Class op2); //перегрузка бинарных операций
 Class operator - (Class op2);
 Class operator = (Class op2); //op1 передается неявно, дсотупен через this
 Class operator ++ (); //префиксный ++
 Class operator ++ (int); //постфиксный ++
 friend Class operator * (Class op1, Class op2); //перегрузка бинарной операции "другом" класса
 friend Class operator + (Class op1, int n); //коммутативная перегрузка
 friend Class operator + (int n, Class op2); //сложения с числом с помощью 2 "друзей"
 friend Class operator -- (Class& op); //префиксный --
 friend Class operator -- (Class& op, int); //и постфиксный --, перегруженные "друзьями"
 void operator () (int n, ...); //перегружаем оператор вызова функций
};

void Class::show(void) { cout << this->n << endl; }
void Class::show(const char* s) { cout << s << " " << this->n << endl; }

Class Class::operator + (Class op2) { //бинарное сложение
 Class op;
 op.n = this->n + op2.n;
 return op;
}

Class operator + (Class op1, int n) {
 Class op;
 op.n = op1.n + n;
 return op;
}

Class operator + (int n, Class op2) {
 Class op;
 op.n = n + op2.n;
 return op;
 //А проще вместо этих трёх одной строкой: 
 //return (op2+n);
}

Class operator * (Class op1, Class op2) { //бинарное умножение "другом" класса
 Class op;
 op.n = op1.n * op2.n;
 return op;
}

Class Class::operator - (Class op2) { //бинарное вычитание
 Class op;
 op.n = this->n - op2.n;
 return op;
}

Class Class::operator = (Class op2) { //присваивание
 this->n = op2.n;
 return *this;
}

Class Class::operator ++ () { //префиксный ++
 this->n++; return *this;
}

Class Class::operator ++ (int unused) { //постфиксный ++
 Class op = *this;
 this->n++;
 return op;
}

Class operator -- (Class& op) { //префиксный -- функцией-другом
 op.n--;
 return op;
}

Class operator -- (Class& op, int unused) { //постфиксный -- функцией-другом
 Class op0 = op;
 op.n--;
 return op0;
}

void Class::operator () (int n, ...) {
 int* item = &n;
 for (; n; n--) this->n += *++item;
}

int main() {
 Class a, b, c;
 a.set(1);
 b = c = a;
 a.show("A"); b.show("B"); c.show("C");
 b = a++; b.show("B=A++"); a.show("A");
 c = ++b; c.show("C=++B"); b.show("B");
 Class d = ++c++ + c; d.show("d=++c+++c"); c.show("C");
 Class e = a * c * d; e.show("E=A*C*D");
 Class f = e + 2; f.show("F=E+2");
 Class g = 1 + e; g.show("G=1+E");
 a = --e; a.show("A=--E"); e.show("E");
 b = e--; b.show("B=E--"); e.show("E");
 Class h; h.set(0);
 h(5, 1, 2, 3, 4, 5); h.show("H");
 Class i, j, k;
 i.set(1); j.set(2); k.set(3);
 i = j = k;
 i.show("i=j+=k");
 system("pause>nul");
 return 0;
}

Примечание. В новых компиляторах показанная в операторной функции () работа с переменным списком аргументов может уже не поддерживаться, а понадобится

#include <stdarg.h>

и примерно такой код:

void Class::operator () (int n, ...) {
 int result = 0;
 va_list factor;         //указатель va_list
 va_start(factor, n);    // устанавливаем указатель
 for (int i = 0; i < n; i++) {
  result += va_arg(factor, int);  // получаем значение текущего параметра типа int
 }
 va_end(factor); // завершаем обработку параметров
 this->n = result;
}

03.04.2014, 19:40 [13900 просмотров]


теги: c++ программирование

К этой статье пока нет комментариев, Ваш будет первым