Вспомним еще раз весь список операторов в C++
Все операторы, за исключением ?:
, .
, ::
можно перегружать.
Операторы ||
, &&
, ,
не рекомендуется перегружать так как для них стандарт предусматривает порядок вычисления операндов (слева направо), а для первых двух еще и так называемую семантику быстрых вычислений (short-circuit evaluation), но для перегруженных операторов это уже не гарантируется или просто бессмысленно.
Рассмотри на примере простого класс Vector:
struct Vector {
double x;
double y;
};
Операторы можно перегружать в двух вариантах: как функцию внутри класса и как свободную функцию. Четыре оператора можно перегрузить только как функцию внутри класса — это =, ->, [], (). Для перечислений операторы можно перегружать только как свободные функции.
Для того, чтобы перегрузить оператор как функцию внутри класса необходимо объявить нестатическую функцию с именем operator@, где @ символ(ы) оператора. В случае перегрузки унарного оператора эта функция не должна иметь параметров, а в случае бинарного должна иметь ровно один параметр. В случае перегрузки оператора () эта функция может иметь произвольное число параметров.
Для того, чтобы перегрузить оператор как свободную функцию, необходимо объявить функцию с именем operator@, где @ символ(ы) оператора. В случае перегрузки унарного оператора, эта функция должна иметь один параметр, а в случае бинарного должна иметь два параметра. В случае перегрузки бинарного оператора — по крайней мере один из двух параметров, а в случае унарного единственный параметр должен быть того же типа (или типа ссылки), что и тип, для которого реализуется перегрузка. Так же эта функция должна находится в том же пространстве имен, что и тип, для которого реализуется перегрузка Пример свободных функций:
// унарный минус
Vector operator-(Vector const& v) {
return Vector(-v.x, -v.y);
}
// бинарный плюс
Vector operator+(Vector const& v, Vector const& w) {
return Vector(v.x + w.x, v.y + w.y);
}
// перегрузка умножение на число справа
Vector operator*(Vector const& v, double d) {
return Vector(v.x * d, v.y * d);
}
// перегрузка умножение на число слева
Vector operator*(double d, Vector const& v) {
return v * d;
}
Аналогично, часть операторов можно объявить и внутри класса:
struct Vector {
double x;
double y;
Vector operator-() const { return Vector (-x, -y); }
// бинарный минус. Аргумент всегда справа
Vector operator-(Vector const& v) const {
return Vector(x – v.x, y – v.y);
}
Vector& operator*=(double d) {
x *= d;
y *=d;
return *this;
}
double operator[] (int i) const {
return i == 0 ? x : y;
}
// операторы имитирующие вызов функций. Например:
// Vector sample(5,6);
// sample(3);
// sample(4, 5);
bool operator()(double d) const { /*… */ }
void operator()(double a, double b) { /*… */ }
};
Оператор инкремента (++
) и дикремента (--
) имеют префиксную и постфиксную запись. Напомню, на этом примере:
int k = 5;
int l = k++;
cout << k << " " << l; // 6 5
int m = ++k;
cout << k << " " << m; // 7 7
Чтобы задать форму (префиксного/постфиксного) данных операторов необходимо задать флаговое обозначение (int)
в объявлении перегрузки:
struct Counter {
Counter& operator++() { // prefix
//...
return *this;
}
Counter operator++(int) { //postfix
Counter temp(*this);
++(*this);
return temp;
}
};
#include <iostream>
struct Vector { /*...*/ };
istream& operator>>(istream& is, Vector &p) {
is >> p.x >> p.y;
return is;
}
ostream& operator<<(ostream& os, Vector const& p) {
os << p.x << " " << p.y;
return os;
}
struct Vector {
double x;
double y;
operator double() const {
return sqrt(x * x + y * y);
}
};
//...
Vector v(2, 3);
cout << (double)v; // 4
bool operator==(Vector const& x, Vector const& b) { return … }
bool operator!=(Vector const& x, Vector const& b) { return ! (a == b); }
bool operator<(Vector const& x, Vector const& b) { return … }
bool operator>(Vector const& x, Vector const& b) { return b < a; }
bool operator<=(Vector const& x, Vector const& b) { return !(b < a); }
bool operator>=(Vector const& x, Vector const& b) { return !(a < b); }