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

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

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

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

Рік:
2017
Тип роботи:
Звіт про виконання розрахункової роботи
Предмет:
Об’єктно-орієнтоване програмування
Група:
КІ 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:07

Коментарі

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

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

Нічого не вибрано
0%

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

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

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

Admin

26.02.2023 12:38

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