Menu
Coddy logo textTech

演算子のオーバーロード

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

演算子のオーバーロードを使用すると、+-== などの演算子がカスタムクラスでどのように動作するかを定義できます。point1.Add(point2) のようなメソッドを呼び出す代わりに、より自然な point1 + point2 と記述できます。

演算子をオーバーロードするには、operatorキーワードを使用して特殊な静的メソッドを作成します。

public class Vector
{
    public int X { get; }
    public int Y { get; }
    
    public Vector(int x, int y)
    {
        X = x;
        Y = y;
    }
    
    public static Vector operator +(Vector a, Vector b)
    {
        return new Vector(a.X + b.X, a.Y + b.Y);
    }
}

これで、ベクトルを自然に加算できるようになります:

Vector v1 = new Vector(3, 4);
Vector v2 = new Vector(1, 2);
Vector v3 = v1 + v2;  // X = 4, Y = 6

メソッドは public static である必要があり、少なくとも1つのパラメータは、それを含む型である必要があります。算術演算子 (+, -, *, /)、比較演算子 (==, !=, <, >)、および単項演算子 (-, !, ++) をオーバーロードできます。

比較演算子はペアでオーバーロードする必要があることに注意してください。== を定義する場合は、!= も定義する必要があります。

演算子のオーバーロードは、コードをより直感的にする場合、特にベクトル、複素数、通貨などの数学的な型に対して使用してください。操作の意味がすぐに理解できない場合は、避けるようにしてください。

challenge icon

チャレンジ

簡単

演算子のオーバーロードを通じて、分数の扱いを自然に感じさせる Fraction クラスを作成しましょう。fraction1.Add(fraction2) のようなメソッドを呼び出す代わりに、直感的な fraction1 + fraction2 と書けるようになります。

コードは2つのファイルに分けて構成します:

  • Fraction.cs: Math 名前空間内に、分子と分母を表す Fraction クラスを作成します。この分数クラスには以下のものを含める必要があります:
    • 2つの読み取り専用の整数プロパティ:NumeratorDenominator
    • 分子と分母を(その順番で)受け取るコンストラクタ
    • 次の公式を使用して2つの分数を加算する、オーバーロードされた + 演算子:(a/b) + (c/d) = (a*d + c*b) / (b*d)
    • 2つの分数を乗算する、オーバーロードされた * 演算子:(a/b) * (c/d) = (a*c) / (b*d)
    • 2つの分数が等しい場合に true を返す、オーバーロードされた == 演算子(比較にはたすき掛けを使用します:a*d == c*b
    • == をオーバーロードする際に必須となる、== の逆を返すオーバーロードされた != 演算子
    • 分数を "{Numerator}/{Denominator}" の形式の文字列として返す GetDisplay() メソッド
  • Program.cs: メインファイルで、入力値を使用して2つの分数を作成します。それらを加算、乗算し、等しいかどうかをチェックすることで、オーバーロードされた演算子の動作を実演してください。演算子が自然に機能していることを示すために、結果を出力します。

4つの入力を受け取ります:

  • 1つ目の分数の分子(整数)
  • 1つ目の分数の分母(整数)
  • 2つ目の分数の分子(整数)
  • 2つ目の分数の分母(整数)

出力は以下の形式で表示してください:

Fraction 1: {GetDisplay()}
Fraction 2: {GetDisplay()}
Sum: {GetDisplay()}
Product: {GetDisplay()}
Are equal: {True/False}

例えば、入力が 1224 の場合、出力は以下のようになります:

Fraction 1: 1/2
Fraction 2: 2/4
Sum: 8/8
Product: 2/8
Are equal: True

1*4 == 2*2 であるため、1/22/4 が等しいと認識されていることに注目してください。和と積は簡約(約分)せずに計算されますが、このチャレンジではそれで問題ありません。素晴らしいのは、慣れ親しんだ演算子を使って、いかに自然に分数を扱えるようになったかという点です!

チートシート

演算子のオーバーロードを使用すると、自作のクラスに対して +-*== などの演算子のカスタム動作を定義できます。

演算子をオーバーロードするには、operator キーワードを使用して public static メソッドを作成します。少なくとも1つのパラメータは、そのメソッドを含む型である必要があります。

public class Vector
{
    public int X { get; }
    public int Y { get; }
    
    public Vector(int x, int y)
    {
        X = x;
        Y = y;
    }
    
    public static Vector operator +(Vector a, Vector b)
    {
        return new Vector(a.X + b.X, a.Y + b.Y);
    }
}

使用例:

Vector v1 = new Vector(3, 4);
Vector v2 = new Vector(1, 2);
Vector v3 = v1 + v2;  // X = 4, Y = 6

以下の演算子をオーバーロードできます:

  • 算術演算子: +, -, *, /
  • 比較演算子: ==, !=, <code><, (ペアでオーバーロードする必要があります)
  • 単項演算子: -, !, ++

== をオーバーロードする場合は、!= もオーバーロードする必要があります。

public static bool operator ==(Vector a, Vector b)
{
    return a.X == b.X && a.Y == b.Y;
}

public static bool operator !=(Vector a, Vector b)
{
    return !(a == b);
}

自分で試してみよう

using System;
using Math;

class Program
{
    public static void Main(string[] args)
    {
        // 最初の分数の入力を読み込む
        int num1 = Convert.ToInt32(Console.ReadLine());
        int den1 = Convert.ToInt32(Console.ReadLine());
        
        // 2番目の分数の入力を読み込む
        int num2 = Convert.ToInt32(Console.ReadLine());
        int den2 = Convert.ToInt32(Console.ReadLine());
        
        // TODO: 入力値を使用して2つのFractionオブジェクトを作成する
        
        // TODO: オーバーロードされた + 演算子を使用して分数を加算する
        
        // TODO: オーバーロードされた * 演算子を使用して分数を乗算する
        
        // TODO: オーバーロードされた == 演算子を使用して等価性をチェックする
        
        // TODO: 必要な形式で出力を表示する:
        // Fraction 1: {GetDisplay()}
        // Fraction 2: {GetDisplay()}
        // Sum: {GetDisplay()}
        // Product: {GetDisplay()}
        // Are equal: {True/False}
    }
}
quiz icon腕試し

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

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