Menu
Coddy logo textTech

算術演算子のオーバーロード

CoddyのC++ジャーニー「オブジェクト指向プログラミング」セクションの一部 — レッスン 41/104。

+-*/ などの算術演算子は、カスタムクラスを組み込みの数値型のように動作させるために、一般的にオーバーロードされます。これらの演算子は通常、オペランドを修正するのではなく、新しいオブジェクトを返します。

算術演算子を備えた Fraction クラスは以下の通りです:

class Fraction {
    int numerator, denominator;
    
public:
    Fraction(int n, int d) : numerator(n), denominator(d) {}
    
    Fraction operator+(const Fraction& other) const {
        return Fraction(
            numerator * other.denominator + other.numerator * denominator,
            denominator * other.denominator
        );
    }
    
    Fraction operator*(const Fraction& other) const {
        return Fraction(numerator * other.numerator, 
                        denominator * other.denominator);
    }
};

両方の演算子は、どちらのオペランドも変更しないため、const とマークされていることに注意してください。これらは結果を含む新しい Fraction を作成して返します。

+= のような複合代入演算子の場合、パターンが異なります。これらは左オペランドを修正し、それへの参照を返します:

Fraction& operator+=(const Fraction& other) {
    numerator = numerator * other.denominator + other.numerator * denominator;
    denominator = denominator * other.denominator;
    return *this;
}

一般的な慣行は、複合代入演算子を使用して基本演算子を実装し、コードの重複を減らすことです:

Fraction operator+(const Fraction& other) const {
    Fraction result = *this;    // このオブジェクトをコピーする
    result += other;            // 複合代入を使用する
    return result;
}

このアプローチにより、両方の演算子の一貫性が保たれ、メンテナンスが容易になります。

challenge icon

チャレンジ

簡単

算術演算子のオーバーロードを使用して通貨計算を処理する Money クラスを作成しましょう。通常の数値と同じように自然に金額を扱えるように、複数の算術演算子を実装します。

コードを整理するために、2つのファイルを作成します。

  • Money.h: 浮動小数点の精度問題を避けるために、金額をセント単位(int 型)で保持する Money クラスを定義します。クラスは以下の機能をサポートする必要があります。
    • ドルとセントを別々の整数として受け取るコンストラクタ
    • ドル部分を返すゲッター getDollars()
    • セント部分(0-99)を返すゲッター getCents()
    • 新しい Money オブジェクトを返すオーバーロードされた + および - 演算子
    • 現在のオブジェクトを修正し、その参照を返すオーバーロードされた += および -= 複合代入演算子
    • 金額を $X.YY の形式(セントは常に2桁)で表示する display() メソッド

    レッスンで示したように、コードの重複を減らすために、基本演算子(+ および -)を複合代入演算子を用いて実装してください。すべての算術演算子は、適切な場所に const を指定する必要があります。

  • main.cpp: 2つの金額を表す4つの整数(dollars1、cents1、dollars2、cents2 を別々の行から)を入力から読み取ります。2つの Money オブジェクトを作成し、すべての演算子の動作を実演してください。
    • "Amount 1: " に続いて、1つ目の金額を表示します
    • "Amount 2: " に続いて、2つ目の金額を表示します
    • 2つの金額を加算し、"Sum: " に続いて結果を表示します
    • 1つ目から2つ目を減算し、"Difference: " に続いて結果を表示します
    • += を使用して2つ目の金額を1つ目に加え、"After +=: " に続いて変更された1つ目の金額を表示します

display() メソッドでは、<iomanip>std::setw(2)std::setfill('0') を使用して、セントが常に2桁で表示されるようにしてください(例:$5.7 ではなく $5.07)。

入力文字列を整数に変換するには std::stoi() を使用します。ヘッダーファイルにはインクルードガードを忘れないでください。

チートシート

+-*/ などの算術演算子は、カスタムクラスを組み込みの数値型のように動作させるためにオーバーロードできます。これらの演算子は通常、オペランドを修正するのではなく、新しいオブジェクトを返します。

基本的な算術演算子は、どちらのオペランドも変更しないため、const としてマークする必要があります:

Fraction operator+(const Fraction& other) const {
    return Fraction(
        numerator * other.denominator + other.numerator * denominator,
        denominator * other.denominator
    );
}

+=-= などの複合代入演算子は、左側のオペランドを修正し、それへの参照を返します:

Fraction& operator+=(const Fraction& other) {
    numerator = numerator * other.denominator + other.numerator * denominator;
    denominator = denominator * other.denominator;
    return *this;
}

コードの重複を減らすために、複合代入演算子を使用して基本演算子を実装するのが一般的な方法です:

Fraction operator+(const Fraction& other) const {
    Fraction result = *this;    // このオブジェクトをコピー
    result += other;            // 複合代入を使用
    return result;
}

自分で試してみよう

#include <iostream>
#include <string>
#include "Money.h"

using namespace std;

int main() {
    // 2つの金額の入力を読み込む
    string line;
    
    getline(cin, line);
    int dollars1 = stoi(line);
    
    getline(cin, line);
    int cents1 = stoi(line);
    
    getline(cin, line);
    int dollars2 = stoi(line);
    
    getline(cin, line);
    int cents2 = stoi(line);
    
    // TODO: 入力値を使用して2つの Money オブジェクトを作成する
    
    // TODO: "Amount 1: " に続いて、1つ目の金額を表示する
    
    // TODO: "Amount 2: " に続いて、2つ目の金額を表示する
    
    // TODO: 2つの金額を加算し、"Sum: " に続いて結果を表示する
    
    // TODO: 1つ目から2つ目を減算し、"Difference: " に続いて結果を表示する
    
    // TODO: += を使用して2つ目の金額を1つ目に加え、"After +=: " に続いて変更された1つ目の金額を表示する
    
    return 0;
}
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

オブジェクト指向プログラミングのすべてのレッスン