Промышленное производство
Промышленный Интернет вещей | Промышленные материалы | Техническое обслуживание и ремонт оборудования | Промышленное программирование |
home  MfgRobots >> Промышленное производство >  >> Industrial programming >> Язык C

Перегрузка операторов в 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) {
        // тело функции
    }
    // ...
};

Здесь:


Перегрузка унарных операторов

Унарные операторы работают с одним операндом. Примеры: инкремент ++ и декремент --.


Пример 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.

Примечание: При перегрузке операторов можно заставить их работать как угодно — например, увеличивать значение на 100. Но это запутывает код. Программист должен использовать перегрузку последовательно и интуитивно.

Приведённый пример работает только для префиксной формы. Для постфиксной используется синтаксис:

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
Перегрузка операторов в C++: практические примеры и лучшие практики

Функция оператора:

Complex operator + (const Complex& obj) { /* код */ }

Можно было написать и так:

Complex operator + (Complex obj) { /* код */ }

Но:


Важные правила перегрузки операторов в C++

  1. Два оператора = и & уже перегружены по умолчанию. Для копирования объектов одного класса можно просто использовать = — отдельная функция не нужна.
  2. Перегрузка не может изменить приоритет и ассоциативность операторов. Для изменения порядка вычислений используйте скобки.
  3. Существует 4 оператора, которые нельзя перегрузить в C++:
    1. :: (разрешение области видимости)
    2. . (доступ к члену)
    3. .* (доступ к члену через указатель на функцию)
    4. ?: (тернарный оператор)

Рекомендуемые темы для изучения:

Язык C

  1. Операторы C# — исчерпывающее руководство по операторам в C#
  2. Тернарный оператор в C#: краткое руководство по условным выражениям
  3. Освоение перегрузки методов в C#: концепции, примеры и лучшие практики
  4. Освоение перегрузки конструкторов в C#
  5. Освоение операторов C++: полное руководство с практическими примерами
  6. Комментарии в C++: лучшие практики для читаемого и поддерживаемого кода
  7. Шаблоны классов в C++: практическое руководство
  8. Перегрузка операторов в Python: практическое руководство
  9. Операторы в C++: типы, примеры и практические программы
  10. Перегрузка операторов в C++: практическое руководство с примерами кода