Sobrecarga de operadores en C++ / Sudo Null IT News

¡Hola Habr! En este artículo, veremos una de las características más poderosas de C++: sobrecarga del operador. Esta característica de idioma le permite cambiar el comportamiento de los operadores estándar para tipos de datos personalizados.

Por ejemplo, en lugar de llamar al método add() para agregar dos objetos, simplemente puedes escribir object1 + object2. Suena genial, ¿no? Averigüemos cómo hacer esto.

Lo esencial

Establezcamos algunas reglas básicas para la sobrecarga de operadores:

  1. Sólo sobrecargue a los operadores razonables. Por ejemplo, no podrá sobrecargar al operador. . (para acceder a miembros) o ?: (operador ternario). Asegúrese de que la sobrecarga realmente tenga sentido para su clase.

  2. Pistas para la intuición. Si sobrecarga al operador +sus colegas esperarán que se use para sumar en lugar de, por ejemplo, restar.

  3. Evite la ambigüedad. Nadie quiere lidiar con código que se comporta de manera extraña. Por lo tanto, intente crear un comportamiento inequívoco para los operadores sobrecargados.

La sintaxis para la sobrecarga de operadores tiene este aspecto:

return_type operator op (parameters);

Dónde return_type es el tipo de devolución op es el operador que estás sobrecargando, y parameters — parámetros aceptados por el operador.

Veamos cómo podemos sobrecargar operadores aritméticos para una clase personalizada. Imaginemos que hay una clase. Complexque describe números complejos. Así es como podría verse:

#include 

class Complex {
private:
    double real; // Действительная часть
    double imag; // Мнимая часть

public:
    // Конструктор
    Complex(double r = 0, double i = 0) : real(r), imag(i) {}

    // Перегрузка оператора сложения
    Complex operator+(const Complex& other) {
        return Complex(real + other.real, imag + other.imag);
    }

    // Перегрузка оператора вычитания
    Complex operator-(const Complex& other) {
        return Complex(real - other.real, imag - other.imag);
    }

    // Перегрузка оператора умножения
    Complex operator*(const Complex& other) {
        return Complex(real * other.real - imag * other.imag,
                       real * other.imag + imag * other.real);
    }

    // Перегрузка оператора деления
    Complex operator/(const Complex& other) {
        double denominator = other.real * other.real + other.imag * other.imag;
        return Complex((real * other.real + imag * other.imag) / denominator,
                       (imag * other.real - real * other.imag) / denominator);
    }

    // Метод для вывода комплексного числа
    void display() const {
        std::cout << real << " + " << imag << "i" << std::endl;
    }
};

int main() {
    Complex c1(3, 2);
    Complex c2(1, 7);
    
    Complex sum = c1 + c2;
    sum.display(); // 4 + 9i

    Complex diff = c1 - c2;
    diff.display(); // 2 - 5i

    Complex prod = c1 * c2;
    prod.display(); // -11 + 23i

    Complex quot = c1 / c2;
    quot.display(); // 0.47 - 0.29i

    return 0;
}

Tampoco se olvide de características especiales como operator<<que te hacen la vida mucho más fácil.

Copiar constructores y operador de asignación.

Si su clase usa asignación de memoria dinámica, asegúrese de implementar un constructor de copia y un operador de asignación. Esto ayudará a evitar problemas de doble liberación que pueden ocurrir si te olvidas de estos mecanismos.

Un ejemplo de un constructor de copia simple:

Vector(const Vector& other) : data(other.data) {}

Y un operador de asignación de ejemplo:

Vector& operator=(const Vector& other) {
    if (this != &other) {
        data = other.data; // Правильное копирование
    }
    return *this;
}

Sobrecarga profunda

Ahora veamos la sobrecarga de operadores para trabajar con vectores y matrices. Un vector es simplemente un conjunto ordenado de valores, mientras que una matriz es una matriz bidimensional. Creemos una clase para trabajar con vectores y operadores de sobrecarga para suma y resta.

Aquí hay una clase de ejemplo. Vector:

#include 
#include 

class Vector {
private:
    std::vector data;

public:
    Vector(int size) : data(size) {}

    // Перегрузка оператора сложения
    Vector operator+(const Vector& other) {
        if (data.size() != other.data.size()) {
            throw std::invalid_argument("Vectors must be of the same size");
        }
        Vector result(data.size());
        for (size_t i = 0; i < data.size(); ++i) {
            result.data(i) = data(i) + other.data(i);
        }
        return result;
    }

    // Перегрузка оператора вычитания
    Vector operator-(const Vector& other) {
        if (data.size() != other.data.size()) {
            throw std::invalid_argument("Vectors must be of the same size");
        }
        Vector result(data.size());
        for (size_t i = 0; i < data.size(); ++i) {
            result.data(i) = data(i) - other.data(i);
        }
        return result;
    }

    // Метод для вывода вектора
    void display() const {
        for (const auto& val : data) {
            std::cout << val << " ";
        }
        std::cout << std::endl;
    }
};

int main() {
    Vector v1(3);
    Vector v2(3);
    
    v1 = Vector({1.0, 2.0, 3.0});
    v2 = Vector({4.0, 5.0, 6.0});
    
    Vector sum = v1 + v2;
    sum.display(); // 5.0 7.0 9.0

    Vector diff = v1 - v2;
    diff.display(); // -3.0 -3.0 -3.0

    return 0;
}

Sobrecarga de operadores de entrada y salida

Sobrecarga del operador << y >> es una de las características más útiles de C++. Nos permite mostrar nuestras clases en pantalla y leerlas desde el stream. Agreguemos estas sobrecargas a nuestra clase. Vector.

Así es como puedes implementarlo:

#include 
#include 

class Vector {
private:
    std::vector data;

public:
    Vector(int size) : data(size) {}

    // Перегрузка оператора вывода
    friend std::ostream& operator<<(std::ostream& os, const Vector& v) {
        os << "( ";
        for (const auto& val : v.data) {
            os << val << " ";
        }
        os << ")";
        return os;
    }

    // Перегрузка оператора ввода
    friend std::istream& operator>>(std::istream& is, Vector& v) {
        for (auto& val : v.data) {
            is >> val;
        }
        return is;
    }
};

// Пример использования
int main() {
    Vector v(3);
    std::cout << "Введите три значения для вектора: ";
    std::cin >> v; // Ввод значений в вектор
    std::cout << "Вывод вектора: " << v << std::endl; // Вывод вектора
    return 0;
}

Ahora puede ingresar y generar vectores tan fácilmente como los tipos de datos integrados:

Vector v(3);
std::cin >> v; // Ввод значений в вектор
std::cout << v; // Вывод вектора

En conclusión, permítanme recordarles las lecciones abiertas que se llevarán a cabo en octubre como parte del curso “C++ Developer Professional”:

Publicaciones Similares

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *