Перегрузка операторов сравнения
Часть раздела Объектно-ориентированное программирование путешествия по C++ на Coddy. Урок 42 из 104.
Операторы сравнения, такие как ==, !=, <, >, <= и >=, позволяют сравнивать объекты ваших пользовательских классов. Эти операторы возвращают bool, и их следует пометить как const, поскольку они не изменяют ни один из операндов.
class Date {
int year, month, day;
public:
Date(int y, int m, int d) : year(y), month(m), day(d) {}
bool operator==(const Date& other) const {
return year == other.year &&
month == other.month &&
day == other.day;
}
bool operator<(const Date& other) const {
if (year != other.year) return year < other.year;
if (month != other.month) return month < other.month;
return day < other.day;
}
};Полезный приём — реализовать остальные операторы сравнения через те, которые вы уже определили. После того как у вас есть == и <, остальные следуют естественным образом:
bool operator!=(const Date& other) const {
return !(*this == other);
}
bool operator>(const Date& other) const {
return other < *this;
}
bool operator<=(const Date& other) const {
return !(other < *this);
}
bool operator>=(const Date& other) const {
return !(*this < other);
}Этот подход уменьшает дублирование кода и гарантирует согласованную работу всех операторов сравнения. Если позже вы измените принцип работы равенства или оператора «меньше», остальные операторы автоматически останутся синхронизированными.
Задание
ЛегкоДавайте создадим класс Version, представляющий номера версий программного обеспечения (например, 2.1.0 или 3.0.5) и поддерживающий все шесть операторов сравнения. Это практический пример, в котором сравнение версий определяет, какая версия программного обеспечения новее, — идеально для практики перегрузки операторов сравнения.
Вы создадите два файла, чтобы организовать код:
Version.h: определите классVersion, который хранит три целых числа, представляющих номера версий major, minor и patch. Ваш класс должен поддерживать:- конструктор, принимающий значения major, minor и patch
- геттеры для каждого компонента:
getMajor(),getMinor(),getPatch()(все const) - все шесть операторов сравнения:
==,!=,<,>,<=,>= - метод
toString(), возвращающий версию в виде строки в формате"major.minor.patch"
Реализуйте
==и<напрямую, затем определите остальные четыре оператора через эти два. Для сравнения «меньше чем» сначала сравнивайте major, затем minor, если значения major равны, и затем patch, если и major, и minor равны. Все операторы сравнения должны быть константными функциями-членами.main.cpp: считайте из входных данных шесть целых чисел, представляющих две версии (major1, minor1, patch1, major2, minor2, patch2 в отдельных строках). Создайте два объектаVersionи сравните их с помощью всех ваших операторов.Формат вывода:
Version 1: <v1> Version 2: <v2> v1 == v2: <true/false> v1 != v2: <true/false> v1 < v2: <true/false> v1 > v2: <true/false> v1 <= v2: <true/false> v1 >= v2: <true/false>Выводите
trueилиfalse(в нижнем регистре) для каждого результата сравнения.
Ключевой приём здесь — реализация четырёх производных операторов (!=, >, <=, >=) с использованием только == и <. Это уменьшает дублирование кода и гарантирует согласованность всех операторов, если вы когда-либо измените логику сравнения.
Преобразуйте входные строки в целые числа с помощью std::stoi(). Используйте std::to_string() для создания строки версии. Не забудьте о защите от повторного включения в заголовочном файле.
Попробуйте сами
#include <iostream>
#include <string>
#include "Version.h"
using namespace std;
int main() {
// Прочитать шесть целых чисел для двух версий
string line;
getline(cin, line);
int major1 = stoi(line);
getline(cin, line);
int minor1 = stoi(line);
getline(cin, line);
int patch1 = stoi(line);
getline(cin, line);
int major2 = stoi(line);
getline(cin, line);
int minor2 = stoi(line);
getline(cin, line);
int patch2 = stoi(line);
// TODO: Создать два объекта Version
// TODO: Вывести Version 1 и Version 2 с помощью toString()
// TODO: Сравнить с использованием всех шести операторов и вывести результаты
// Используйте "true" или "false" (строчными буквами) для каждого сравнения
// Формат: "v1 == v2: true" или "v1 == v2: false"
return 0;
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Основы ООП
Внешние файлыСборка и компиляция C++Заголовочные файлы и файлы исходного кодаПространства имен и область видимостиВведение в ООП на C++Классы и объектыУказатель 'this'Методы (функции-члены)Атрибуты (члены данных)Основы конструкторов и деструкторовИтоги — Простой калькулятор4Свойства классов
Члены экземпляра против статическихГеттеры и сеттерыКонстантные функции-членыКлючевое слово mutableСтатические методы и переменныеДружественные функции и классыИтоги — Менеджер банковских счетов7Наследование
Основы наследованияУровни доступа при наследованииПорядок вызова конструкторов и деструкторовПереопределение методовВиртуальные функции и VTableМножественное наследованиеВиртуальное наследованиеИтоги — Иерархия сотрудников10Обзор STL
Обзор и философия STLКонтейнеры STLИтераторыАлгоритмы STLФункторы и лямбда-выраженияИтоги: частота слов13Паттерны проектирования. Часть 1
Введение в паттерны проектированияПаттерн SingletonFactory и Abstract FactoryПаттерн BuilderПаттерн ObserverПаттерн Strategy2Управление памятью
Стек и кучаУказатели и ссылкиДинамическая память (new/delete)Умные указатели в C++RAII в C++Итоги — Менеджер динамического массива5Инкапсуляция
Спецификаторы доступа в C++Спецификаторы доступа: подробный разборСокрытие данныхStruct против ClassВложенные и внутренние классыИтоги — Система учета студентов8Полиморфизм
Полиморфизм компиляции и времени выполненияПерегрузка функцийВиртуальные функции: повторениеЧистые виртуальные функцииАбстрактные классыПроектирование интерфейсов на C++Dynamic Casting и RTTIИтоги: Калькулятор фигур11Продвинутые концепции ООП
Композиция против наследованияМиксины через CRTPИдиома PimplСтирание типовEnum Classes и строгая типизацияОбработка исключений в ООППользовательские иерархии исключений14Паттерны проектирования. Часть 2
Паттерн КомандаПаттерн АдаптерПаттерн ДекораторПаттерн Шаблонный методПаттерн СостояниеПаттерн КомпоновщикRAII как паттерн3Конструкторы и деструкторы
Конструктор по умолчаниюПараметризованный конструкторКонструктор копированияКонструктор перемещенияСписки инициализации конструктораДелегирующие конструкторыГлубокое погружение в деструкторыПравило трех / пяти / нуляПовторение — класс String6Перегрузка операторов
Введение в перегрузку операторовПерегрузка арифметических операторовПерегрузка операторов сравненияОператоры потоковПерегрузка оператора присваиванияПерегрузка операторов [] и ()Операторы преобразования типовИтоги — класс Matrix9Шаблоны
Шаблоны функцийШаблоны классовСпециализация шаблоновВариативные шаблоныОсновы SFINAE и Type TraitsИтоги — Обобщенный контейнерПотренируйтесь самостоятельно: Онлайн-компилятор C++