Вы находитесь на странице: 1из 9

Министерство Образования Республики Молдова

Технический Университет Молдовы

ОТЧЁТ
О ВЫПОЛНЕНИИ ЛАБОРАТОРНОЙ РАБОТЫ
по предмету ООП

Выполнила Михайлова Н.,гр.IBM-222

Проверил Митителу В.

Кишинев,2023
ЛАБОРАТОРНАЯ РАБОТА №3
Тема: Перегрузка операторов
Цели работы:
● изучение необходимости перегрузки операторов;
● изучение синтаксиса определения операторов;
● изучение типов операторов;
● изучение форм перегрузки;

1. Являются ли операторы абсолютно необходимыми?


​ Операторы не являются абсолютно необходимыми, но они позволяют создавать более
удобный и читаемый код в объектно-ориентированном программировании на C++.
​ 2. Какие зарезервированные слова используются для определения
операторов?
​ Зарезервированные слова для определения операторов в C++ включают "+", "-", "*", "/",
"new", "delete" и другие.
​ 3. Могут ли операторы не возвращать результат?
​ Да, операторы могут не возвращать результат, например, операторы присваивания "="
и инкремента/декремента "++" и "--".
​ 4. Как классифицируются операторы?
​ Операторы классифицируются как унарные (работают с одним операндом), бинарные
(работают с двумя операндами) и тернарные (работают с тремя операндами).
​ 5. Как компилятор различает префиксную и постфиксную запись унарных
операторов?
​ Компилятор различает префиксную и постфиксную запись унарных операторов на
основе их положения относительно операнда (например, "++i" и "i++").
​ 6. Какие операторы нельзя перегружать?
​ Некоторые операторы, такие как точка (".") и размер оператора (sizeof), нельзя
перегружать.
​ 7. Каков синтаксис вызова операторов?
​ Синтаксис вызова операторов в C++ осуществляется с использованием оператора как
метода класса или через дружественную функцию, например: "объект.оператор()" или
"оператор(операнд1, операнд2)".
​ 8. Как используется оператор "()"?
​ Оператор "()" используется для создания объектов, которые могут быть вызваны как
функции.
​ 9. Как используется оператор "->"?
​ Оператор "->" используется для доступа к членам объекта по указателю или через
объект, представляющий собой указатель.
​ 10. Зачем нужны две формы перегрузки (как метод класса и как дружественная
функция)?
​ Две формы перегрузки операторов, как метод класса и как дружественная функция,
нужны для обеспечения разных способов работы с операторами, включая операторы,
которые не являются членами класса.
​ 11. Какому типу принадлежит оператор вывода в поток "<<"?
​ Оператор вывода в поток "<<" принадлежит типу ostream, который используется для
вывода данных в поток.
​ 12. В каких случаях обязательно определять оператор присваивания?
​ Оператор присваивания необходимо определять, когда класс содержит динамические
ресурсы, чтобы правильно управлять памятью и предотвратить утечки памяти.

Вариант 8

а) Определить класс Complex – комплексные числа. Определить все


односимвольные операторы как дружественные операторы, а двухсимвольные как
методы класса. Исключение – оператор присваивания, который может быть
только методом класса и операторы вводы/вывода в поток. Сложение и вычитание
должно производиться как с комплексными числами, так и со встроенным double.

#include <iostream>

class Complex {
private:
double real;
double imaginary;

public:
Complex(double real = 0.0, double imaginary = 0.0)
: real(real), imaginary(imaginary) {}

// Методы класса для сложения и вычитания с другими комплексными числами


Complex operator+(const Complex& other) const {
return Complex(real + other.real, imaginary + other.imaginary);
}

Complex operator-(const Complex& other) const {


return Complex(real - other.real, imaginary - other.imaginary);
}

// Методы класса для сложения и вычитания с встроенным double


Complex operator+(const double& num) const {
return Complex(real + num, imaginary);
}

Complex operator-(const double& num) const {


return Complex(real - num, imaginary);
}

// Дружественные операторы для односимвольных операций


friend Complex operator*(const Complex& c1, const Complex& c2);
friend Complex operator/(const Complex& c1, const Complex& c2);

// Метод класса для оператора присваивания


Complex& operator=(const Complex& other) {
if (this == &other) {
return *this;
}
real = other.real;
imaginary = other.imaginary;
return *this;
}

// Вывод комплексного числа в поток


friend std::ostream& operator<<(std::ostream& out, const Complex& c);

// Ввод комплексного числа из потока


friend std::istream& operator>>(std::istream& in, Complex& c);
};

// Дружественный оператор для умножения


Complex operator*(const Complex& c1, const Complex& c2) {
double realPart = c1.real * c2.real - c1.imaginary * c2.imaginary;
double imagPart = c1.real * c2.imaginary + c1.imaginary * c2.real;
return Complex(realPart, imagPart);
}

// Дружественный оператор для деления


Complex operator/(const Complex& c1, const Complex& c2) {
double denominator = c2.real * c2.real + c2.imaginary * c2.imaginary;
double realPart = (c1.real * c2.real + c1.imaginary * c2.imaginary) / denominator;
double imagPart = (c1.imaginary * c2.real - c1.real * c2.imaginary) / denominator;
return Complex(realPart, imagPart);
}

// Оператор вывода в поток


std::ostream& operator<<(std::ostream& out, const Complex& c) {
out << c.real << " + " << c.imaginary << "i";
return out;
}

// Оператор ввода из потока


std::istream& operator>>(std::istream& in, Complex& c) {
in >> c.real >> c.imaginary;
return in;
}

int main() {
Complex a(3.0, 4.0);
Complex b(1.0, 2.0);

Complex result1 = a + b; // Сложение комплексных чисел


Complex result2 = a - b; // Вычитание комплексных чисел
Complex result3 = a + 2.5; // Сложение с double
Complex result4 = a - 1.0; // Вычитание из double
std::cout << "a + b = " << result1 << std::endl;
std::cout << "a - b = " << result2 << std::endl;
std::cout << "a + 2.5 = " << result3 << std::endl;
std::cout << "a - 1.0 = " << result4 << std::endl;

return 0;
}

b) Создать класс Stack – стек, используя динамическую память. Определить


операторы "+" – сложения стеков, "=" – присваивания, "()" – выдачи нового стека,
содержащего последние n элементов - как методы класса. Определить операторы
сравнения - "==", "!=", "<", ">", как дружественные функции. Для реализации последних
двух операторов определить функцию, вычисляющую норму элементов стека.
Определить операторы ввода/вывода в поток.

#include <iostream>
#include <cmath> // Включаем заголовок для sqrt

class Stack {
private:
int* elements; // Динамический массив для хранения элементов стекаs
int size; // Текущий размер стека
int capacity; //Максимальная емкость стека

public:
// Конструктор
Stack(int initialCapacity = 10) {
capacity = initialCapacity;
size = 0;
elements = new int[capacity];
}

// Деструктор
~Stack() {
delete[] elements;
}

// Метод переноса элемента в стек


void push(int element) {
if (size == capacity) {
// Если стек переполнен, изменить размер массива
int* newElements = new int[capacity * 2];
for (int i = 0; i < size; i++) {
newElements[i] = elements[i];
}
delete[] elements;
elements = newElements;
capacity *= 2;
}
elements[size++] = element;
}

// Метод извлечения элемента из стека


int pop() {
if (size == 0) {
throw std::out_of_range("Stack is empty");
}
return elements[--size];
}

// Метод получения последних n элементов в виде нового стека


Stack operator()(int n) {
Stack newStack(n);
for (int i = size - n; i < size; i++) {
newStack.push(elements[i]);
}
return newStack;
}

// Перегрузка операторов для сложения стеков


Stack operator+(const Stack& other) {
Stack newStack(size + other.size);
for (int i = 0; i < size; i++) {
newStack.push(elements[i]);
}
for (int i = 0; i < other.size; i++) {
newStack.push(other.elements[i]);
}
return newStack;
}

// Перегрузка операторов для присваивания


Stack& operator=(const Stack& other) {
if (this != &other) {
delete[] elements;
capacity = other.capacity;
size = other.size;
elements = new int[capacity];
for (int i = 0; i < size; i++) {
elements[i] = other.elements[i];
}
}
return *this;
}

// Операторы сравнения как дружественные функции


friend bool operator==(const Stack& stack1, const Stack& stack2) {
if (stack1.size != stack2.size) {
return false;
}
for (int i = 0; i < stack1.size; i++) {
if (stack1.elements[i] != stack2.elements[i]) {
return false;
}
}
return true;
}

friend bool operator!=(const Stack& stack1, const Stack& stack2) {


return !(stack1 == stack2);
}

friend bool operator<(const Stack& stack1, const Stack& stack2) {


int norm1 = stack1.calculateNorm();
int norm2 = stack2.calculateNorm();
return norm1 < norm2;
}

friend bool operator>(const Stack& stack1, const Stack& stack2) {


return stack2 < stack1;
}

// Операторы ввода/вывода
friend std::ostream& operator<<(std::ostream& os, const Stack& stack) {
for (int i = 0; i < stack.size; i++) {
os << stack.elements[i] << " ";
}
return os;
}

friend std::istream& operator>>(std::istream& is, Stack& stack) {


int element;
while (is >> element) {
stack.push(element);
}
return is;
}

private:
// Вспомогательная функция для вычисления нормы элементов стека
int calculateNorm() const {
int norm = 0;
for (int i = 0; i < size; i++) {
norm += elements[i] * elements[i];
}
return norm;
}
};

int main() {
Stack stack1(5);
stack1.push(1);
stack1.push(2);
stack1.push(3);

Stack stack2(3);
stack2.push(4);
stack2.push(5);

// Пример использования операторов и методов


Stack stack3 = stack1 + stack2;
Stack stack4 = stack3(2);

std::cout << "Stack 1: " << stack1 << std::endl;


std::cout << "Stack 2: " << stack2 << std::endl;
std::cout << "Stack 3: " << stack3 << std::endl;
std::cout << "Stack 4: " << stack4 << std::endl;

if (stack1 == stack2) {
std::cout << "Stack 1 is equal to Stack 2" << std::endl;
} else {
std::cout << "Stack 1 is not equal to Stack 2" << std::endl;
}

if (stack1 < stack2) {


std::cout << "Stack 1 is less than Stack 2" << std::endl;
} else if (stack1 > stack2) {
std::cout << "Stack 1 is greater than Stack 2" << std::endl;
} else {
std::cout << "Stack 1 and Stack 2 have the same norm" << std::endl;
}

return 0;
}

Вам также может понравиться