Przeciążanie operatorów porównania
Część sekcji Programowanie obiektowe ścieżki C++ w Coddy. Lekcja 42 z 104.
Operatory porównania, takie jak ==, !=, <, >, <= i >=, pozwalają porównywać obiekty własnych klas. Operatory te zwracają wartość bool i powinny być oznaczone jako const, ponieważ nie modyfikują żadnego z operandów.
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;
}
};Przydatną techniką jest zaimplementowanie pozostałych operatorów porównania na podstawie tych, które zostały już zdefiniowane. Gdy masz już == i <, reszta wynika z tego naturalnie:
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);
}To podejście ogranicza powielanie kodu i zapewnia spójne działanie wszystkich operatorów porównania. Jeśli później zmienisz sposób działania operatora równości lub mniejszości, pozostałe operatory automatycznie będą działać spójnie.
Wyzwanie
ŁatwyZbudujmy klasę Version, która reprezentuje numery wersji oprogramowania (takie jak 2.1.0 lub 3.0.5) i obsługuje wszystkie sześć operatorów porównania. To praktyczny przykład zastosowania, w którym porównywanie wersji pozwala określić, które oprogramowanie jest nowsze — idealny do ćwiczenia przeciążania operatorów porównania.
Utworzysz dwa pliki, aby uporządkować swój kod:
Version.h: Zdefiniuj klasęVersion, która przechowuje trzy liczby całkowite reprezentujące numery wersji: główny, poboczny i poprawkowy. Twoja klasa powinna obsługiwać:- Konstruktor, który przyjmuje wartości głównej, pobocznej i poprawkowej wersji
- Gettery dla każdego składnika:
getMajor(),getMinor(),getPatch()(wszystkie const) - Wszystkie sześć operatorów porównania:
==,!=,<,>,<=,>= - Metodę
toString(), która zwraca wersję jako ciąg znaków w formacie"major.minor.patch"
Zaimplementuj bezpośrednio operatory
==i<, a następnie zdefiniuj pozostałe cztery operatory na podstawie tych dwóch. Przy porównaniu mniejszości najpierw porównaj główny numer wersji, następnie poboczny, jeśli numery główne są równe, a potem poprawkowy, jeśli zarówno główne, jak i poboczne numery są równe. Wszystkie operatory porównania powinny być stałymi funkcjami składowymi.main.cpp: Wczytaj z wejścia sześć liczb całkowitych reprezentujących dwie wersje (major1, minor1, patch1, major2, minor2, patch2, każdą w osobnym wierszu). Utwórz dwa obiektyVersioni porównaj je za pomocą wszystkich swoich operatorów.Format wyjściowy:
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>Dla każdego wyniku porównania wypisz
truelubfalse(małymi literami).
Kluczową techniką jest tutaj zaimplementowanie czterech operatorów pochodnych (!=, >, <=, >=) przy użyciu wyłącznie == i <. Ogranicza to powielanie kodu i zapewnia spójność wszystkich operatorów, jeśli kiedykolwiek zmienisz logikę porównywania.
Konwertuj ciągi wejściowe na liczby całkowite za pomocą std::stoi(). Do utworzenia ciągu znaków wersji użyj std::to_string(). Nie zapomnij o strażnikach nagłówka w pliku nagłówkowym.
Spróbuj swoich sił
#include <iostream>
#include <string>
#include "Version.h"
using namespace std;
int main() {
// Wczytaj sześć liczb całkowitych dla dwóch wersji
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: Utwórz dwa obiekty Version
// TODO: Wyświetl Version 1 i Version 2 za pomocą toString()
// TODO: Porównaj za pomocą wszystkich sześciu operatorów i wyświetl wyniki
// Użyj "true" lub "false" (małymi literami) dla każdego porównania
// Format: "v1 == v2: true" lub "v1 == v2: false"
return 0;
}
Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.
Wszystkie lekcje w sekcji Programowanie obiektowe
1Podstawy programowania obiektowego
Pliki zewnętrzneBudowanie i kompilacja C++Pliki nagłówkowe i pliki źródłowePrzestrzenie nazw i zakresWprowadzenie do programowania obiektowego w C++Klasy a obiektyWskaźnik „this”Metody (funkcje składowe)Atrybuty (składowe danych)Podstawy konstruktorów i destruktorówPowtórzenie – prosty kalkulator4Właściwości klas
Elementy instancji a elementy statyczneGettery i setteryStałe funkcje składoweSłowo kluczowe mutableMetody i zmienne statyczneFunkcje i klasy zaprzyjaźnionePodsumowanie – menedżer konta bankowego7Dziedziczenie
Podstawy dziedziczeniaPoziomy dostępu w dziedziczeniuKolejność wywołań konstruktora i destruktoraNadpisywanie metodFunkcje wirtualne i VTableWielokrotne dziedziczenieDziedziczenie wirtualnePowtórzenie — hierarchia pracowników2Zarządzanie pamięcią
Pamięć stosu a stertyWskaźniki i referencjePamięć dynamiczna (new/delete)Inteligentne wskaźniki w C++RAII w C++Podsumowanie — menedżer tablicy dynamicznej5Hermetyzacja
Specyfikatory dostępu w C++Specyfikatory dostępu — szczegółowoUkrywanie informacjiStruktura a klasaKlasy zagnieżdżone i wewnętrznePodsumowanie — system ewidencji studentów8Polimorfizm
Polimorfizm czasu kompilacji i wykonaniaPrzeciążanie funkcjiFunkcje wirtualne — powtórkaCzysto wirtualne funkcjeKlasy abstrakcyjneProjektowanie interfejsów w C++Rzutowanie dynamiczne i RTTIPodsumowanie — kalkulator kształtów3Konstruktory i destruktory
Konstruktor domyślnyKonstruktor z parametramiKonstruktor kopiującyKonstruktor przenoszącyListy inicjalizacyjne konstruktoraKonstruktory delegująceDestruktor — szczegółowe omówienieZasada trzech / pięciu / zeraPodsumowanie — klasa String6Przeciążanie operatorów
Wprowadzenie do przeciążania operatorówPrzeciążanie operatorów arytmetycznychPrzeciążanie operatorów porównaniaOperatory strumieniowePrzeciążanie operatora przypisaniaPrzeciążanie operatorów [] i ()Operatory konwersji typówPodsumowanie — klasa Matrix9Szablony
Szablony funkcjiSzablony klasSpecjalizacja szablonówSzablony wariadycznePodstawy SFINAE i cech typówPodsumowanie — kontener generycznyPoćwicz samodzielnie: Kompilator C++ online