Перегрузка операторов в C++: практические примеры и лучшие практики
Перегрузка операторов в C++
В этом руководстве мы изучим перегрузку операторов на примерах — от унарных до бинарных, с правильными возвращаемыми типами и const-корректностью.
В C++ мы можем изменить поведение операторов для пользовательских типов — классов и структур. Это называется перегрузкой операторов. Например,
Предположим, у нас есть три объекта c1, c2 и result класса Complex, представляющего комплексные числа.
Благодаря перегрузке операторов мы можем переопределить оператор + для сложения комплексных чисел, написав просто:
result = c1 + c2;
вместо чего-то вроде:
result = c1.addNumbers(c2);
Это делает код интуитивным и понятным.
int, float, char и т.д.).Синтаксис перегрузки операторов в C++
Для перегрузки оператора используется специальная функция operator. Она определяется внутри класса или структуры, чьи объекты будут работать с перегруженным оператором.
class ClassName {
// ...
public:
returnType operator symbol (arguments) {
// тело функции
}
// ...
};
Здесь:
returnType— возвращаемый тип функции.operator— ключевое слово.symbol— перегружаемый оператор:+,<,-,++и т.д.arguments— аргументы функции.
Перегрузка унарных операторов
Унарные операторы работают с одним операндом. Примеры: инкремент ++ и декремент --.
Пример 1: Перегрузка префиксного оператора ++
// Перегрузка ++ как префикса
#include <iostream>
using namespace std;
class Count {
private:
int value;
public:
// Конструктор: инициализация значением 5
Count() : value(5) {}
// Перегрузка префиксного ++
void operator ++ () {
++value;
}
void display() {
cout << "Count: " << value << endl;
}
};
int main() {
Count count1;
// Вызов "void operator ++ ()"
++count1;
count1.display();
return 0;
}
Вывод
Count: 6
При использовании ++count1 вызывается void operator ++ (), увеличивающее value на 1.
Приведённый пример работает только для префиксной формы. Для постфиксной используется синтаксис:
void operator ++ (int) { // код }
Обратите внимание на int в скобках — это специальный синтаксис для обозначения постфиксной формы, а не параметр функции.
Пример 2: Перегрузка префиксного и постфиксного ++
// Перегрузка ++ как префикса и постфикса
#include <iostream>
using namespace std;
class Count {
private:
int value;
public:
Count() : value(5) {}
// Префиксный ++
void operator ++ () {
++value;
}
// Постфиксный ++
void operator ++ (int) {
value++;
}
void display() {
cout << "Count: " << value << endl;
}
};
int main() {
Count count1;
// Вызов "void operator ++ (int)"
count1++;
count1.display();
// Вызов "void operator ++ ()"
++count1;
count1.display();
return 0;
}
Вывод
Count: 6 Count: 7
Пример 2 работает для обеих форм. Но он не сработает, если попытаться сделать так:
Count count1, result;
// Ошибка
result = ++count1;
Проблема в типе возвращаемого значения — void. Решается это возвратом объекта Count:
// Возврат Count для префиксного ++
Count operator ++ () { /* код */ }
// Возврат Count для постфиксного ++
Count operator ++ (int) { /* код */ }
Пример 3: Возврат значения из функции оператора (++)
#include <iostream>
using namespace std;
class Count {
private:
int value;
public:
Count() : value(5) {}
// Префиксный ++ с возвратом
Count operator ++ () {
Count temp;
temp.value = ++value;
return temp;
}
// Постфиксный ++ с возвратом
Count operator ++ (int) {
Count temp;
temp.value = value++;
return temp;
}
void display() {
cout << "Count: " << value << endl;
}
};
int main() {
Count count1, result;
// Префиксный ++
result = ++count1;
result.display();
// Постфиксный ++
result = count1++;
result.display();
return 0;
}
Вывод
Count: 6 Count: 6
Для префиксного оператора:
Count operator ++ () {
Count temp;
temp.value = ++value;
return temp;
}
Постфиксный вариант аналогичен. Создаётся временный объект temp, который возвращается. Обратите внимание: temp.value = ++value; — переменная value принадлежит вызывающему объекту count1, а temp.value — временному объекту.
Перегрузка бинарных операторов
Бинарные операторы работают с двумя операндами. Например:
result = num + 9;
При перегрузке бинарного оператора для пользовательских типов:
obj3 = obj1 + obj2;
Функция оператора вызывается для объекта obj1, а obj2 передаётся как аргумент.
Пример 4: Перегрузка бинарного оператора +
// C++ программа для перегрузки бинарного оператора +
// Сложение двух комплексных чисел
#include <iostream>
using namespace std;
class Complex {
private:
float real;
float imag;
public:
// Конструктор
Complex() : real(0), imag(0) {}
void input() {
cout << "Enter real and imaginary parts respectively: ";
cin >> real;
cin >> imag;
}
// Перегрузка оператора +
Complex operator + (const Complex& obj) {
Complex temp;
temp.real = real + obj.real;
temp.imag = imag + obj.imag;
return temp;
}
void output() {
if (imag < 0)
cout << "Output Complex number: " << real << imag << "i";
else
cout << "Output Complex number: " << real << "+" << imag << "i";
}
};
int main() {
Complex complex1, complex2, result;
cout << "Enter first complex number:\n";
complex1.input();
cout << "Enter second complex number:\n";
complex2.input();
// complex1 вызывает функцию оператора, complex2 передаётся как аргумент
result = complex1 + complex2;
result.output();
return 0;
}
Вывод
Enter first complex number: Enter real and imaginary parts respectively: 9 5 Enter second complex number: Enter real and imaginary parts respectively: 7 6 Output Complex number: 16+11i

Функция оператора:
Complex operator + (const Complex& obj) { /* код */ }
Можно было написать и так:
Complex operator + (Complex obj) { /* код */ }
Но:
- Использование
&делает код эффективным — передаётся ссылка на complex2, а не создаётся копия. const— хорошая практика, предотвращает изменение complex2 внутри функции.
Важные правила перегрузки операторов в C++
- Два оператора
=и&уже перегружены по умолчанию. Для копирования объектов одного класса можно просто использовать=— отдельная функция не нужна. - Перегрузка не может изменить приоритет и ассоциативность операторов. Для изменения порядка вычислений используйте скобки.
- Существует 4 оператора, которые нельзя перегрузить в C++:
::(разрешение области видимости).(доступ к члену).*(доступ к члену через указатель на функцию)?:(тернарный оператор)
Рекомендуемые темы для изучения:
- Как правильно перегрузить оператор инкремента?
- Как перегрузить бинарный оператор - для вычитания комплексных чисел?
Язык C
- Операторы C# — исчерпывающее руководство по операторам в C#
- Тернарный оператор в C#: краткое руководство по условным выражениям
- Освоение перегрузки методов в C#: концепции, примеры и лучшие практики
- Освоение перегрузки конструкторов в C#
- Освоение операторов C++: полное руководство с практическими примерами
- Комментарии в C++: лучшие практики для читаемого и поддерживаемого кода
- Шаблоны классов в C++: практическое руководство
- Перегрузка операторов в Python: практическое руководство
- Операторы в C++: типы, примеры и практические программы
- Перегрузка операторов в C++: практическое руководство с примерами кода