Принципи перевантаження операторів порівняння ті ж самі, що і в перевантаженні інших операторів, які ми розглядали на попередніх уроках. Оскільки всі оператори порівняння є бінарними і не змінюють свої ліві операнди, то виконувати перевантаження потрібно через дружні функції.
Наприклад, перевантажимо оператор рівності ==
і оператор нерівності !=
для класу Car:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
#include <iostream> #include <string> class Car { private: std::string m_company; std::string m_model; public: Car(std::string company, std::string model) : m_company(company), m_model(model) { } friend bool operator== (const Car &c1, const Car &c2); friend bool operator!= (const Car &c1, const Car &c2); }; bool operator== (const Car &c1, const Car &c2) { return (c1.m_company == c2.m_company && c1.m_model== c2.m_model); } bool operator!= (const Car &c1, const Car &c2) { return !(c1== c2); } int main() { Car mustang("Ford", "Mustang"); Car logan("Renault", "Logan"); if (mustang == logan) std::cout << "Mustang and Logan are the same.\n"; if (mustang != logan) std::cout << "Mustang and Logan are not the same.\n"; return 0; } |
Все просто. Оскільки результат виконання оператора !=
є прямо протилежним результату виконання оператора ==
, то ми визначили оператор !=
, використовуючи вже перевантажений оператор ==
(зменшивши, таким чином, кількість коду, складність і можливість виникнення помилок).
А як щодо операторів <
і >
? Тут потрібно визначитися, чим один об’єкт класу Car може бути кращим за інший об’єкт класу Car, і як це все відобразити в коді. Неочевидно! Тому тут ми і не перевантажували оператори <
і >
.
Порада: Не перевантажуйте оператори, які є зайвими для вашого класу.
Однак, оператори <
і >
можна використовувати для сортування списку автомобілів (об’єктів класу Car) в алфавітному порядку, використовуючи члени m_company
і m_model
, тому завжди розглядайте різні варіанти.
Деякі класи-контейнери Стандартної бібліотеки C++ вимагають перевантаження оператора <
, щоб вони могли зберігати відсортовані елементи.
Перевантажимо оператори порівняння >
, <
, >=
і <=
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
#include <iostream> class Dollars { private: int m_dollars; public: Dollars(int dollars) { m_dollars = dollars; } friend bool operator> (const Dollars &d1, const Dollars &d2); friend bool operator<= (const Dollars &d1, const Dollars &d2); friend bool operator< (const Dollars &d1, const Dollars &d2); friend bool operator>= (const Dollars &d1, const Dollars &d2); }; bool operator> (const Dollars &d1, const Dollars &d2) { return d1.m_dollars > d2.m_dollars; } bool operator>= (const Dollars &d1, const Dollars &d2) { return d1.m_dollars >= d2.m_dollars; } bool operator< (const Dollars &d1, const Dollars &d2) { return d1.m_dollars < d2.m_dollars; } bool operator<= (const Dollars &d1, const Dollars &d2) { return d1.m_dollars <= d2.m_dollars; } int main() { Dollars ten(10); Dollars seven(7); if (ten > seven) std::cout << "Ten dollars are greater than seven dollars.\n"; if (ten >= seven) std::cout << "Ten dollars are greater than or equal to seven dollars.\n"; if (ten < seven) std::cout << "Seven dollars are greater than ten dollars.\n"; if (ten <= seven) std::cout << "Seven dollars are greater than or equal to ten dollars.\n"; return 0; } |
Все просто.
Але, як ви вже могли б помітити, оператори >
і <=
є логічними протилежностями, тому один з них можна було б визначити через інший. Та ж ситуація і з <
і >=
. Але, оскільки визначення функцій перевантаження настільки прості, а оператори в рядку оголошення функції так добре поєднуються з операторами в рядку повернення результату, ми вирішили цього не робити.
Тест
Завдання №1
Використовуючи вищенаведений клас Dollars перепишіть оператори <
і <=
, використовуючи їх логічні протилежності.
Відповідь №1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
#include <iostream> class Dollars { private: int m_dollars; public: Dollars(int dollars) { m_dollars = dollars; } friend bool operator> (const Dollars &d1, const Dollars &d2); friend bool operator<= (const Dollars &d1, const Dollars &d2); friend bool operator< (const Dollars &d1, const Dollars &d2); friend bool operator>= (const Dollars &d1, const Dollars &d2); }; bool operator> (const Dollars &d1, const Dollars &d2) { return d1.m_dollars > d2.m_dollars; } bool operator>= (const Dollars &d1, const Dollars &d2) { return d1.m_dollars >= d2.m_dollars; } // Логічною протилежністю оператора < є >=, тому ми можемо просто інвертувати результат виконання >= bool operator< (const Dollars &d1, const Dollars &d2) { return !(d1 >= d2); } // Логічною протилежністю оператора <= є >, тому ми можемо просто інвертувати результат виконання > bool operator<= (const Dollars &d1, const Dollars &d2) { return !(d1 > d2); } int main() { Dollars ten(10); Dollars seven(7); if (ten > seven) std::cout << "Ten dollars are greater than seven dollars.\n"; if (ten >= seven) std::cout << "Ten dollars are greater than or equal to seven dollars.\n"; if (ten < seven) std::cout << "Seven dollars are greater than ten dollars.\n"; if (ten <= seven) std::cout << "Seven dollars are greater than or equal to ten dollars.\n"; return 0; } |
Завдання №2
Додайте перевантаження операторів <<
і <
в клас Car, представлений вище, щоб наступний фрагмент коду:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
#include <iostream> #include <string> #include <vector> #include <algorithm> int main() { std::vector<Car> v; v.push_back(Car("Ford", "Mustang")); v.push_back(Car("Renault", "Logan")); v.push_back(Car("Ford", "Ranger")); v.push_back(Car("Renault", "Duster")); std::sort(v.begin(), v.end()); // потрібне перевантаження оператора < для класу Car for (auto &car : v) std::cout << car << '\n'; // потрібне перевантаження оператора << для класу Car return 0; } |
Видавав наступний результат:
(Ford, Mustang)
(Ford, Ranger)
(Renault, Duster)
(Renault, Logan)
Відповідь №2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
#include <iostream> #include <string> #include <vector> #include <algorithm> class Car { private: std::string m_company; std::string m_model; public: Car(std::string company, std::string model) : m_company(company), m_model(model) { } friend bool operator== (const Car &c1, const Car &c2); friend bool operator!= (const Car &c1, const Car &c2); friend std::ostream& operator<< (std::ostream& out, const Car & c) { out << '(' << c.m_company << ", " << c.m_model << ')'; return out; } friend bool operator<(const Car &c1, const Car &c2) { if (c1.m_company < c2.m_company) return true; if (c1.m_company > c2.m_company) return false; if (c1.m_model < c2.m_model) return true; if (c1.m_model > c2.m_model) return false; return false; } }; bool operator== (const Car &c1, const Car &c2) { return (c1.m_company == c2.m_company && c1.m_model == c2.m_model); } bool operator!= (const Car &c1, const Car &c2) { return !(c1 == c2); } int main() { std::vector<Car> v; v.push_back(Car("Ford", "Mustang")); v.push_back(Car("Renault", "Logan")); v.push_back(Car("Ford", "Ranger")); v.push_back(Car("Renault", "Duster")); std::sort(v.begin(), v.end()); // потрібне перевантаження оператора < для класу Car for (auto &car : v) std::cout << car << '\n'; // потрібне перевантаження оператора << для класу Car return 0; } |