Лабораторная работа 7 "Перегрузка операций"
1. Что такое перегрузка операций?
Перегрузка операций - это возможность в C++ определять собственное поведение для стандартных операторов (+, -, *, /, =, == и др.) при работе с пользовательскими типами данных (классами).
Пример без перегрузки:
Complex c1, c2, c3; c3 = c1.add(c2); // Неудобно!
Пример с перегрузкой:
Complex c1, c2, c3; c3 = c1 + c2; // Естественно и понятно!
2. Два способа перегрузки
Способ 1: Методы класса
Оператор становится методом класса. Левый операнд - это текущий объект (this).
class Complex {
public:
// Метод класса - левый операнд this, правый other
Complex operator+(const Complex& other) const {
return Complex(real + other.real, imag + other.imag);
}
};Когда использовать:
Когда левый операнд ОБЯЗАТЕЛЬНО объект вашего класса
Для операций, где текущий объект - главный
Способ 2: Дружественные функции
Отдельные функции, объявленные как friend, имеют доступ к приватным полям.
class Complex {
private:
double real, imag;
public:
// Объявление дружественной функции
friend Complex operator+(const Complex& c1, const Complex& c2);
};
// Реализация дружественной функции
Complex operator+(const Complex& c1, const Complex& c2) {
return Complex(c1.real + c2.real, c1.imag + c2.imag);
}Когда использовать:
Когда левый операнд НЕ объект вашего класса
Для симметричных операций (5 + obj и obj + 5)
Когда нужен доступ к приватным полям с двух сторон
3. Синтаксис перегрузки
Для методов класса:
ReturnType operator#(Parameters) const; // # - оператор (+, -, *, / и т.д.)
Для дружественных функций:
friend ReturnType operator#(Parameter1, Parameter2);
4. Возвращаемые значения
Арифметические операторы (+, -, *, /) → возвращают новый объект
Операторы присваивания (=, +=, -=) → возвращают ссылку на текущий объект
Операторы сравнения (==, !=, <, >) → возвращают bool
5. Особые случаи
Унарные операторы:
// Префиксный ++ (метод класса)
Complex& operator++() {
real++; imag++;
return *this;
}Операторы ввода/вывода:
// Только через дружественные функции!
friend ostream& operator<<(ostream& os, const Complex& c) {
os << c.real << " + " << c.imag << "i";
return os;
}6. Правила и ограничения
МОЖНО:
Перегружать большинство операторов
Использовать оба способа перегрузки
Возвращать любые типы
НЕЛЬЗЯ:
Создавать новые операторы
Изменять приоритет операторов
Изменять количество операндов
Перегружать операторы . (точка), .*, ::, ?:
Пример
#include <iostream>
using namespace std;
class Complex {
private:
double real;
double imag;
public:
// Конструктор
Complex(double r = 0, double i = 0) : real(r), imag(i) {}
// Геттеры
double getReal() const { return real; }
double getImag() const { return imag; }
// Вывод числа
void show() const {
cout << real;
if (imag >= 0)
cout << " + " << imag << "i";
else
cout << " - " << -imag << "i";
}
// === ПЕРЕГРУЗКА ЧЕРЕЗ МЕТОДЫ КЛАССА ===
// Сложение комплексных чисел
Complex operator+(const Complex& other) const {
return Complex(real + other.real, imag + other.imag);
}
// Вычитание комплексных чисел
Complex operator-(const Complex& other) const {
return Complex(real - other.real, imag - other.imag);
}
// Умножение комплексных чисел
Complex operator*(const Complex& other) const {
// (a+bi)*(c+di) = (ac-bd) + (ad+bc)i
double r = real * other.real - imag * other.imag;
double i = real * other.imag + imag * other.real;
return Complex(r, i);
}
// === ДРУЖЕСТВЕННЫЕ ФУНКЦИИ ===
// Сложение с целым числом
friend Complex operator+(const Complex& c, double num) {
return Complex(c.real + num, c.imag);
}
// Вычитание целого числа
friend Complex operator-(const Complex& c, double num) {
return Complex(c.real - num, c.imag);
}
// Деление на целое число
friend Complex operator/(const Complex& c, double num) {
if (num == 0) {
cout << "Ошибка: деление на 0!" << endl;
return Complex();
}
return Complex(c.real / num, c.imag / num);
}
};
// Демонстрация работы
int main() {
Complex a(3, 4); // 3 + 4i
Complex b(1, 2); // 1 + 2i
cout << "a = "; a.show(); cout << endl;
cout << "b = "; b.show(); cout << endl << endl;
cout << "МЕТОДЫ КЛАССА:" << endl;
Complex c = a + b; cout << "a + b = "; c.show(); cout << endl;
c = a - b; cout << "a - b = "; c.show(); cout << endl;
c = a * b; cout << "a * b = "; c.show(); cout << endl;
cout << "\nДРУЖЕСТВЕННЫЕ ФУНКЦИИ:" << endl;
c = a + 5; cout << "a + 5 = "; c.show(); cout << endl;
c = a - 2; cout << "a - 2 = "; c.show(); cout << endl;
c = a / 2; cout << "a / 2 = "; c.show(); cout << endl;
return 0;
}ЗАДАНИЯ: Класс Vector2D
Задание 1: Базовые операции
Создайте класс Vector2D для работы с двумерными векторами.
Требования:
Поля класса:
x- координата X (double)y- координата Y (double)
Конструктор:
Vector2D(double x_val = 0, double y_val = 0)
Методы класса (перегрузка через МЕТОДЫ):
Vector2D operator+(const Vector2D& other) const- сложение векторовVector2D operator-(const Vector2D& other) const- вычитание векторовdouble operator*(const Vector2D& other) const- скалярное произведение
Дружественные функции:
friend Vector2D operator+(const Vector2D& v, double num)- с числомfriend Vector2D operator-(const Vector2D& v, double num)- с числомfriend Vector2D operator/(const Vector2D& v, double num)- деление
Вспомогательные методы:
void show() const- вывод вектора
Пример использования:
Vector2D v1(2, 3), v2(1, 4); Vector2D v3 = v1 + v2; // (3, 7) double dot = v1 * v2; // 14 (скалярное произведение) Vector2D v4 = v1 / 2; // (1, 1.5)
Задание 2: Дополнительные операции
Добавьте к классу Vector2D следующие операции:
Методы класса:
bool operator==(const Vector2D& other) const- сравнение на равенствоVector2D operator-() const- унарный минус
Дружественные функции:
friend ostream& operator<<(ostream& os, const Vector2D& v)- вывод в потокfriend Vector2D operator*(const Vector2D& v, double num)- умножение на числоfriend Vector2D operator*(double num, const Vector2D& v)- число на вектор
Пример использования:
Vector2D v1(2, 3), v2(2, 3); if (v1 == v2) cout << "Векторы равны" << endl; cout << v1; // Вывод: (2, 3) Vector2D v3 = -v1; // (-2, -3) Vector2D v4 = v1 * 2; // (4, 6) Vector2D v5 = 3 * v1; // (6, 9)
Задание 3: Расширенные возможности
Добавьте продвинутые операции:
Методы класса:
Vector2D& operator+=(const Vector2D& other)- сложение с присваиваниемVector2D& operator-=(const Vector2D& other)- вычитание с присваиваниемdouble length() const- длина вектора
Дружественные функции:
friend double dotProduct(const Vector2D& v1, const Vector2D& v2)- скалярное произведениеfriend bool arePerpendicular(const Vector2D& v1, const Vector2D& v2)- проверка перпендикулярности
Пример использования:
Vector2D v1(3, 4), v2(1, 0);
v1 += v2; // v1 становится (4, 4)
cout << "Длина: " << v1.length(); // 5.65685
if (arePerpendicular(v1, v2)) {
cout << "Векторы перпендикулярны";
}Подсказки для реализации:
Формулы для векторов:
// Сложение: (x1, y1) + (x2, y2) = (x1+x2, y1+y2) // Вычитание: (x1, y1) - (x2, y2) = (x1-x2, y1-y2) // Скалярное произведение: x1*x2 + y1*y2 (возвращает double!) // Длина вектора: sqrt(x*x + y*y) // Унарный минус: (-x, -y)
Важные моменты:
Проверяйте деление на ноль
Скалярное произведение возвращает double, а не Vector2D
Для operator<< возвращайте ссылку на ostream
Унарный минус создает новый объект
Структура класса:
class Vector2D {
private:
double x, y;
public:
// Конструктор
Vector2D(double x_val = 0, double y_val = 0) : x(x_val), y(y_val) {}
// Ваш код здесь...
// Вспомогательный метод
void show() const {
cout << "(" << x << ", " << y << ")";
}
};