Лабораторна робота №5

Інформація про навчальний заклад

ВУЗ:
Національний університет Львівська політехніка
Інститут:
ІКТА
Факультет:
КН
Кафедра:
Кафедра ЕОМ

Інформація про роботу

Рік:
2024
Тип роботи:
Звіт про виконання розрахункової роботи
Предмет:
Об’єктно-орієнтоване програмування
Група:
КІ 31

Частина тексту файла (без зображень, графіків і формул):

Міністерство освіти і науки України Національний університет „Львівська політехніка” Кафедра ЕОМ / Звіт про виконання лабораторної роботи №5 з дисципліни: “Програмування, частина 2 (Об’єктно-орієнтоване програмування)” на тему:“ Перевантаження операторів” 2017 Мета: познайомитися із перевантаженням операторів. Теоретичні відомості Перевантаження операторів Кожному оператору мова С++ ставить у відповідність ім'я функції, що складається з ключового слова operator, власне оператору та аргументів відповідних типів: тип operator символОператору (списокПараметрів) { //тіло методу }   Щоб використовувати операцію над об'єктами класів, ця операція повинна бути перевантажена, але є два виключення. Операції присвоювання (=) і взяття адреси (&) створюються в класі автоматично за замовчуванням, тому їх можна використовувати без явного перевантаження. За замовчуванням операція присвоювання зводиться до побітового копіювання даних-елементів класу. Проте таке побітове копіювання небезпечне для класів з елементами, що вказують на динамічно виділені області пам'яті, масиви, рядки, оскільки в цьому випадку відбувається копіювання не даних (глибоке копіювання), а лише вказівників на дані (поверхневе копіювання). Для таких класів слід явно перевантажувати операцію присвоювання і здійснювати у ній глибоке копіювання. Операція адресації також може бути використана з об'єктами будь-яких класів без перевантаження. Вона просто повертає адресу об'єкта в пам'яті. Але операцію адресації можна також і перевантажувати. Перевантаження операцій підпорядковується наступним правилам: При перевантаженні зберігаються кількість аргументів, пріоритети операцій та правила асоціації, що використовуються у стандартних типах даних; Для стандартних типів даних операції не підлягають перевизначенню; Перевантажена функція-оператор не може мати параметрів по замовчуванню, не успадковується та не може бути визначеною як static; Функція-оператор може бути визначена трьома способами – метод класу, дружня функція або звичайна функція. В останніх двох випадках вона повинна приймати хоча б один аргумент, що має тип класу, вказівника або посилання на клас. При перевантаженні операцій ( ), [], -> та = функція перевантаження операції може бути оголошена лише як метод класу. Для інших операцій функції перевантаження операцій можуть не бути методами класу. Оператори, які можна перевантажити: + - * / % ^  & | ~ ! , =  < > <= >= ++ --  << >> == != && ||  += -= /= %= ^= &=  |= *= <<= >>= [] ()  -> ->* new new [] delete delete []   Оператори, які не можна перевантажити: sizeof . (селектор елемента структури або класу) * (оператор доступу до елементу за вказівником) :: (оператор дозволу видимості) ?: (тернарний оператор) typeid const_cast dynamic_cast reinterpret_cast static_cast # і ## (символи препроцесору) Коли операція реалізована як метод класу, тоді: - якщо операція є унарною (передбачає один операнд, наприклад, інкременту або []), то лівим операндом вважаєтсья об’єкт, до якого застосовується операція, а правий операнд відсутній, тому метод, що реалізує даний оператор не приймає аргументів, за виключенням кількох операторів (наприклад, постфіксна форма інкременту або декременту). - якщо операція є бінарною (передбачає 2 операнди, наприклад додавання або присвоєння) і лівий операнд є об’єктом класу у якому перевантажується операція, то крайній лівий операнд вважається об’єктом з-під якого здійснюється виклик даного методу (оператора), а правий операнд – передається як параметр, тому для нього слід вказати тип аргумента у методі; перевантажених операторів одного виду може бути кілька в залежності від типу аргументу, що передається методу; Якщо операція є бінарною але лівий операнд не є об’єктом класу у якому перевантажується операція, то дана операція не може бути методом класу, а має бути реалізована як дружня функція, якщо ця функція повинна мати прямий доступ до закритих або захищених елементів цього класу, або звичайна функція в протилежному випадку. Перевантажена операція << повинна мати лівий операнд типу ostream & (такий, як cout), так що вона не може бути функцією-елементом. Аналогічно, перевантажена операція >> повинна мати лівий операнд типу іstream & (такий, як cіn), так що вона теж не може бути функцією-елементом. До того ж кожна з цих перевантажених функцій-операцій може забажати доступу до закритих елементів-даних об'єкта класу, так що ці перевантажені функції-операції роблять функціями-друзями класу. Будь-яку бінарну операцію можна перевантажувати як нестатичний метод з одним аргументом, або як функцію, що не є елементом, із двома аргументами (один з цих аргументів повинен бути або об'єктом класу, або посиланням на об'єкт класу). Унарну операцію класу можна перевантажувати як метод без аргументів, або як функцію, з одним аргументом; цей аргумент повинен бути або об'єктом класу, або посиланням на об'єкт класу. Функції-елементи, що реалізують перевантажені операції, повинні бути нестатичними, щоб вони могли мати доступ до даних класу. Нагадаємо, що статичні методи можуть мати доступ тільки до статичних даних-елементів класу. При перевантаженні унарних операцій переважно створюють методи класу, замість дружніх функцій, що не є членами класу. Дружніх функцій краще уникати доти, поки вони не стануть абсолютно необхідними. Використання друзів порушує інкапсуляцію класу. Щоб перевантажити операцію інкремента та декремента для одержання можливості використання і префіксної, і постфіксної форм, кожна з цих двох перевантажених функцій-операцій повинна мати різну сигнатуру, щоб компілятор мав можливість визначити, яка версія мається на увазі в кожному конкретному випадку. Префіксний варіант перевантажується як будь-яка інша префіксна унарна операція. Для постфіксної форми вводиться додатковий параметр цілого типу у список аргументів, щоб зробити функцію для постфіксного варіанту відмінною від функції для префіксної форми. Зауваження щодо перевантаження операцій: Неможливим є введення власних операторів. Компілятор С++ не розуміє семантики перевантаженого оператору, а отже, не нав'язує жодних математичних концепцій. Можна перевантажити, скажімо, оператор інкременту в якості зменшення аргументу, проте навряд чи в цьому є сенс. Не існує виведення складних операторів з простих: якщо ви перевантажили оператори operator+ та operator=, це зовсім не означає, що С++ обчислить вираз a += b, оскільки ви не перевантажили operator +=. Перевантаження бінарних операторів не тотожньо відносно перестановки аргументів місцями, тим більше, якщо вони різного типу. Синтаксис виклику операторів реалізований у мові С++ таким чином, щоб програміст міг записати операцію над об’єктом класу з звичному для нього вигляді, наприклад object1 += object2. Проте для компілятора такий запис стосовно об’єктів не є звичним, бо дана операція у такому вигляді визначена лише для простих типів, а для об’єкту класу даний виклик має бути перетворений у виклик методу, що оголошений в класі, або у виклик відповідної функції. Тому при компіляції компілятор перетворює даний виклик у виклик відповідного методу або функції за наступним принципом: - якщо оператор реалізований у вигляді методу, то лівий операнд перетворюється в об’єкт з-під якого викликається метод, що реалізує вказаний оператор, а правий операнд, якщо він присутній, передається методу в якості аргументу. - якщо оператор реалізований у вигляді функції або дружньої функції, то воклик операції перетворюєтсья у виклик функції, яка приймає своїм лівим параметром лівий операнд операції, а правим, якщо такий присутній, - правий операнд операції. Розглянемо приклади викликів операторів. Виклик оператору має наступний вигляд: змінна символОператору [змінна];   Наприклад: obj1 = obj2; obj1++; obj1 + 5; 2 * obj1;  Прицьому, якщо оператор визначений як метод класу, то перші 3 виклики будуть перетрансьовані компілятором в наступні виклики: obj1.operator=(obj2); obj1.operator++(); obj1.operator+(5);   Останній виклик реалізується виключно у вигляді дружньої або звичайної функції і після обробки компілятором буде перетворений у наступний виклик дружньої функції: operator*(2, obj1);   Завдання: Написати програму яка буде використовувати перевантаження операторів та продемонструвати їх використання. В дані роботі реалізовано перевантаження наступних операторів: =, +, +=, <<. Оператори =, +, += використовуються для додавання об’єктів класу Train. Оператор << перевантажено для виводу об’єктів класу Train та Car на екран. Код Train.h #pragma once #include <string> #include "car.h" class Train { private: string trainName; int carCount; int freePlaces; vector<Car> cars; public: Train() { this->trainName = ""; this->carCount = 0; this->freePlaces = 0; } Train(string trainName, vector<Car> cars) { this->trainName = trainName; this->cars = cars; this->carCount = cars.size(); int freePlaces = 0; for (int i = 0; i < cars.size(); i++) { for (int j = 0; j < cars[i].getPlaceArray().size(); j++) { if (cars[i].getPlaceArray()[j] == true) { freePlaces++; } } } this->freePlaces = freePlaces; } //Оголошуємо перевантажених операторiв friend ostream& operator<< (ostream& output, Train& train); Train operator+ (Train& train); Train& operator+= (Train& train); Train& operator= (Train& train); //Прописуємо get i set string getTrainName() { return this->trainName; } void setTrainName(string name) { this->trainName = name; } int getCarCount() { return this->carCount; } void setCarCount(int name) { this->carCount = name; } int getFreePlaces() { return this->freePlaces; } void setFreePlaces(int name) { this->freePlaces = name; } vector<Car> getCars() { return this->cars; } void setCars(vector<Car> cars) { this->cars = cars; } }; Код Train.cpp: #include "Train.h" //Перевантажуємо оператор "<<" для виведення даних про поїзд ostream & operator<<(ostream & output, Train & train) { output << "Назва потягу: " << train.getTrainName() << endl; output << "Кiлькiсть вiльних мiсць: " << train.getFreePlaces() << endl; output << "Список вагонiв: " << endl; for (int i = 0; i < train.getCarCount(); i++) { output << train.getCars()[i] << endl; } return output; } //Перевантажуємо оператор "+" щоб додавати поїзди Train Train::operator+(Train & train) { Train myTrain; myTrain.setTrainName(this->getTrainName()); myTrain.setCarCount(this->getCarCount() + train.getCarCount()); myTrain.setFreePlaces(this->getFreePlaces() + train.getFreePlaces()); vector<Car> curr; curr = this->getCars(); for (int i = 0; i < train.getCars().size(); i++) { curr.push_back(train.getCars()[i]); } for (int i = 0; i < myTrain.getCarCount(); i++) { curr[i].setNumber(i + 1); } myTrain.setCars(curr); return myTrain; } //Перевантажуємо оператор "+=" Train & Train::operator+=(Train & train) { Train curr; curr = *this + train; *this = curr; return *this; } //Перевантажуємо оператор "=" Train & Train::operator=(Train & train) { this->setCars(train.getCars()); this->setCarCount(train.getCarCount()); this->setFreePlaces(train.getFreePlaces()); this->setTrainName(train.getTrainName()); return *this; } Код Car.h: #pragma once #include <iostream> #include <vector> using namespace std; class Car { private: int number; int maxPlacesCount; int freePlaces; vector<bool> placeArray; public: Car() { this->number = 0; this->maxPlacesCount = 0; } Car(int numb, vector<bool> placePtr) { this->number = numb; this->maxPlacesCount = placePtr.size(); int freePlaces = 0; for (int i = 0; i < placePtr.size(); i++) { if (placePtr[i] == 1) freePlaces++; } this->freePlaces = freePlaces; this->placeArray = placePtr; } friend ostream& operator<< (ostream& output, Car& car); //Прописуємо get i set int getNumber() { return this->number; } void setNumber(int numb) { this->number = numb; } int getMaxPlacesCount() { return this->maxPlacesCount; } void setMaxPlacesCount(int numb) { this->maxPlacesCount = numb; } vector<bool> getPlaceArray() { return this->placeArray; } void setNumber(vector<bool> numb) { this->placeArray = numb; } }; Код Car.cpp: #include "Car.h" #include <Windows.h> using namespace std; enum ConsoleColor { Black = 0, Blue = 1, Green = 2, Cyan = 3, Red = 4, Magenta = 5, Brown = 6, LightGray = 7, DarkGray = 8, LightBlue = 9, LightGreen = 10, LightCyan = 11, LightRed = 12, LightMagenta = 13, Yellow = 14, White = 15 }; void SetColor(int text, int background) { HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE); SetConsoleTextAttribute(hStdOut, (WORD)((background << 4) | text)); } //Перевантажуємо оператор "<<" для виведення даних про вагон ostream & operator<<(ostream & output, Car & car) { output << " Вагон №" << car.getNumber() << endl; int curr = 0; output << " "; for (int i = 0; i < car.getMaxPlacesCount(); i++) { if (car.getPlaceArray()[i] == true) { SetColor(2, 0); output << ++curr << " "; } else { SetColor(4, 0); output << ++curr << " "; } } SetColor(15, 0); return output; } Код main.cpp: #include "Train.h" #include <Windows.h> void main() { setlocale(0, "ukr"); HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE); SetConsoleTextAttribute(hStdOut, (WORD)((0 << 4) | 15)); // Оголошуємо вагон 1 vector<bool> carPlaces1{ 0, 0, 0, 1, 1, 0, 1, 0, 1 }; Car Car1(1, carPlaces1); //Оголошуємо вагон 2 vector<bool> carPlaces2{ 0, 1, 0, 0, 1, 0, 1, 0, 0 }; Car Car2(2, carPlaces2); //Оголошуємо вагон 3 vector<bool> carPlaces3{ 1, 1, 0, 1, 1, 1, 1, 0, 1 }; Car Car3(3, carPlaces3); //Оголошуємо вагон другого поїзда vector<bool> carPlaces4{ 1, 0, 1, 1, 0, 1, 0, 0, 1 }; Car Car4(1, carPlaces4); //Оголошую вектор з вагонiв для першого поїзду vector<Car> Cars1{ Car1, Car2, Car3 }; //Оголошую вектор з вагона для другого поїзду vector<Car> Cars2{ Car4 }; Train Train2("Lutsk-Odesa", Cars2); Train Train1("Lviv-Odesa", Cars1); cout << "Виводимо вiльнi мiсця першого поїзду" << endl; cout << Train1 << endl; cout << "Виводимо вiльнi мiсця другого поїзду" << endl; cout << Train2 << endl; cout << "Додаємо вагони поїздiв" << endl; //Додаємо поїзди Train train = Train1 + Train2; cout << train << endl; } Результат виконання програми: / Рис.1 - Ескіз екрана виконаної програми(Вивід інформації про поїзди на екран) Висновок: виконуючи п’яту лабораторну роботу я отримав знання та навички у вмінні перевантажувати оператори. Ці навички стануть мені в пригоді при роботі над курсовою роботою.
Антиботан аватар за замовчуванням

02.10.2017 01:10-

Коментарі

Ви не можете залишити коментар. Для цього, будь ласка, увійдіть або зареєструйтесь.

Ділись своїми роботами та отримуй миттєві бонуси!

Маєш корисні навчальні матеріали, які припадають пилом на твоєму комп'ютері? Розрахункові, лабораторні, практичні чи контрольні роботи — завантажуй їх прямо зараз і одразу отримуй бали на свій рахунок! Заархівуй всі файли в один .zip (до 100 МБ) або завантажуй кожен файл окремо. Внесок у спільноту – це легкий спосіб допомогти іншим та отримати додаткові можливості на сайті. Твої старі роботи можуть приносити тобі нові нагороди!
Нічого не вибрано
0%

Оголошення від адміністратора

Антиботан аватар за замовчуванням

Подякувати Студентському архіву довільною сумою

Admin

26.02.2023 12:38

Дякуємо, що користуєтесь нашим архівом!