比較演算子のオーバーロード
CoddyのC++ジャーニー「オブジェクト指向プログラミング」セクションの一部 — レッスン 42/104。
==、!=、<code><、、<=、>= といった比較演算子を使用すると、カスタムクラスのオブジェクトを比較できるようになります。これらの演算子は 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;
}
};便利なテクニックは、すでに定義した比較演算子を使って他の比較演算子を実装することです。== と <code>< があれば、残りは自然に導き出せます:
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);
}このアプローチはコードの重複を減らし、すべての比較演算子が一貫して動作することを保証します。後で等価性や「より小さい」の動作を変更した場合、他の演算子も自動的に同期した状態が保たれます。
チャレンジ
簡単ソフトウェアのバージョン番号(2.1.0や3.0.5など)を表し、6つすべての比較演算子をサポートするVersionクラスを作成しましょう。これは、バージョンを比較してどちらのソフトウェアが新しいかを判断する実用的なユースケースであり、比較演算子のオーバーロードを練習するのに最適です。
コードを整理するために、2つのファイルを作成します。
Version.h: メジャー、マイナー、パッチのバージョン番号を表す3つの整数を格納するVersionクラスを定義します。このクラスは以下をサポートする必要があります。- major、minor、patchの値を受け取るコンストラクタ
- 各コンポーネントのゲッター:
getMajor()、getMinor()、getPatch()(すべてconst) - 6つすべての比較演算子:
==、!=、<、>、<=、>= - バージョンを
"major.minor.patch"の形式の文字列として返すtoString()メソッド
==と<を直接実装し、残りの4つの演算子をこの2つを使って定義します。小なり(less-than)比較では、まずmajorを比較し、majorが等しい場合はminorを比較し、majorとminorの両方が等しい場合はpatchを比較します。すべての比較演算子はconstメンバ関数である必要があります。main.cpp: 2つのバージョンを表す6つの整数(major1、minor1、patch1、major2、minor2、patch2を別々の行で)を入力から読み取ります。2つの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(小文字)を出力します。
ここでの重要なテクニックは、4つの派生演算子(!=、>、<=、>=)を==と<のみを使用して実装することです。これにより、コードの重複が減り、比較ロジックを変更した場合でもすべての演算子の整合性が保たれます。
入力文字列を整数に変換するにはstd::stoi()を使用します。バージョン文字列の構築にはstd::to_string()を使用します。ヘッダーファイルのインクルードガードを忘れないでください。
チートシート
比較演算子 (==, !=, <code><, , <=, >=) を使用すると、カスタムクラスのオブジェクトを比較できます。これらの演算子は 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;
}
};コードの重複を減らし、一貫性を確保するために、他の比較演算子を == と <code>< を使用して実装します。
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);
}自分で試してみよう
#include <iostream>
#include <string>
#include "Version.h"
using namespace std;
int main() {
// 2つのバージョンのために6つの整数を読み込む
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: 2つの Version オブジェクトを作成する
// TODO: toString() を使用して Version 1 と Version 2 を出力する
// TODO: 6つすべての演算子を使用して比較し、結果を出力する
// 各比較には "true" または "false"(小文字)を使用する
// 形式: "v1 == v2: true" または "v1 == v2: false"
return 0;
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
3コンストラクタとデストラクタ
デフォルトコンストラクタ引数付きコンストラクタコピーコンストラクタムーブコンストラクタコンストラクタ初期化リスト委譲コンストラクタデストラクタ詳解Rule of Three / Five / Zeroまとめ - Stringクラス6演算子オーバーロード
演算子オーバーロード入門算術演算子のオーバーロード比較演算子のオーバーロードストリーム演算子代入演算子のオーバーロード[] と () 演算子のオーバーロード型変換演算子まとめ:Matrix クラス