工業製造
産業用モノのインターネット | 工業材料 | 機器のメンテナンスと修理 | 産業プログラミング |
home  MfgRobots >> 工業製造 >  >> Industrial programming >> C言語

C#の演算子オーバーロード:カスタム型で演算子を再定義する

C#で利用可能なほとんどの組み込み演算子を再定義またはオーバーロードできます。これにより、プログラマーはユーザー定義型でも演算子を使用できるようになります。オーバーロードされた演算子は、演算子を定義する記号にキーワードoperatorを続けた特殊な名前を持つ関数です。通常の関数と同様に、オーバーロード演算子には戻り値の型とパラメータリストがあります。

演算子オーバーロードの基本構文

public static 戻り値の型 operator 演算子記号(パラメータリスト) {
    // 実装
}

加算演算子(+)のオーバーロード例

public static Box operator+ (Box b, Box c) {
    Box box = new Box();
    box.length = b.length + c.length;
    box.breadth = b.breadth + c.breadth;
    box.height = b.height + c.height;
    return box;
}

この関数は、ユーザー定義クラスBoxに対する加算演算子(+)を実装します。2つのBoxオブジェクトの属性を加算し、結果のBoxオブジェクトを返します。

完全な実装例

using System;
namespace OperatorOvlApplication {
    class Box {
        private double length;
        private double breadth;
        private double height;
        
        public double GetVolume() {
            return length * breadth * height;
        }
        
        public void SetLength(double len) { length = len; }
        public void SetBreadth(double bre) { breadth = bre; }
        public void SetHeight(double hei) { height = hei; }
        
        // +演算子のオーバーロード
        public static Box operator+ (Box b, Box c) {
            Box box = new Box();
            box.length = b.length + c.length;
            box.breadth = b.breadth + c.breadth;
            box.height = b.height + c.height;
            return box;
        }
    }
    
    class Tester {
        static void Main(string[] args) {
            Box box1 = new Box();
            Box box2 = new Box();
            Box box3 = new Box();
            double volume = 0.0;
            
            box1.SetLength(6.0); box1.SetBreadth(7.0); box1.SetHeight(5.0);
            box2.SetLength(12.0); box2.SetBreadth(13.0); box2.SetHeight(10.0);
            
            volume = box1.GetVolume();
            Console.WriteLine("Volume of Box1 : {0}", volume);  // 210
            
            volume = box2.GetVolume();
            Console.WriteLine("Volume of Box2 : {0}", volume);  // 1560
            
            // 2つのオブジェクトを加算
            box3 = box1 + box2;
            volume = box3.GetVolume();
            Console.WriteLine("Volume of Box3 : {0}", volume);  // 5400
            Console.ReadKey();
        }
    }
}

実行結果:

Volume of Box1 : 210
Volume of Box2 : 1560
Volume of Box3 : 5400

オーバーロード可能・不可能な演算子

No.演算子と説明
1+, -, !, ~, ++, --
単項演算子(1つのオペランド)。オーバーロード可能。
2+, -, *, /, %
二項演算子(2つのオペランド)。オーバーロード可能。
3==, !=, <, >, <=, >=
比較演算子。オーバーロード可能(対で定義推奨)。
4&&, ||
条件論理演算子。直接オーバーロード不可。(true/false演算子と&/|で間接的に制御可能)
5+=, -=, *=, /=, %=
複合代入演算子。直接オーバーロード不可。(対応する二項演算子のオーバーロードで自動的に使用可能)
6=, ., ?:, ->, new, is, sizeof, typeof
オーバーロード不可。

比較演算子のオーバーロード(対で定義必須)

比較演算子(==/!=, </>, <=/>=)は対でオーバーロードする必要があります。

拡張例:比較演算子とToStringのオーバーロード

using System;
namespace OperatorOvlApplication {
    class Box {
        private double length, breadth, height;
        
        public double GetVolume() => length * breadth * height;
        public void SetLength(double len) => length = len;
        public void SetBreadth(double bre) => breadth = bre;
        public void SetHeight(double hei) => height = hei;
        
        // +演算子
        public static Box operator+ (Box b, Box c) => new Box {
            length = b.length + c.length,
            breadth = b.breadth + c.breadth,
            height = b.height + c.height
        };
        
        // == と != (対で必須)
        public static bool operator ==(Box lhs, Box rhs) {
            if (ReferenceEquals(lhs, null) && ReferenceEquals(rhs, null)) return true;
            if (ReferenceEquals(lhs, null) || ReferenceEquals(rhs, null)) return false;
            return lhs.length == rhs.length && lhs.height == rhs.height && lhs.breadth == rhs.breadth;
        }
        
        public static bool operator !=(Box lhs, Box rhs) => !(lhs == rhs);
        
        // < と > (対で必須)
        public static bool operator <(Box lhs, Box rhs) {
            if (ReferenceEquals(lhs, null)) return !ReferenceEquals(rhs, null);
            return lhs.length < rhs.length && lhs.height < rhs.height && lhs.breadth < rhs.breadth;
        }
        
        public static bool operator >(Box lhs, Box rhs) => rhs < lhs;
        
        // <= と >= (対で必須)
        public static bool operator <=(Box lhs, Box rhs) => !(rhs < lhs);
        public static bool operator >=(Box lhs, Box rhs) => !(lhs < rhs);
        
        // Equals/GetHashCodeもオーバーライドすべき
        public override bool Equals(object obj) => obj is Box b && this == b;
        public override int GetHashCode() => HashCode.Combine(length, breadth, height);
        
        // 表示用
        public override string ToString() => $"({length}, {breadth}, {height})";
    }
    
    class Tester {
        static void Main(string[] args) {
            Box box1 = new Box { length = 6, breadth = 7, height = 5 };
            Box box2 = new Box { length = 12, breadth = 13, height = 10 };
            Box box3 = box1 + box2;
            Box box4 = box3;
            
            Console.WriteLine($"Box1: {box1}");
            Console.WriteLine($"Box2: {box2}");
            Console.WriteLine($"Box3: {box3}");
            Console.WriteLine($"Volume Box3: {box3.GetVolume()}");
            
            Console.WriteLine(box1 > box2 ? "Box1 > Box2" : "Box1 <= Box2");
            Console.WriteLine(box1 < box2 ? "Box1 < Box2" : "Box1 >= Box2");
            Console.WriteLine(box1 == box2 ? "Box1 == Box2" : "Box1 != Box2");
            Console.WriteLine(box3 == box4 ? "Box3 == Box4" : "Box3 != Box4");
            Console.ReadKey();
        }
    }
}

実行結果:

Box1: (6, 7, 5)
Box2: (12, 13, 10)
Box3: (18, 20, 15)
Volume Box3: 5400
Box1 <= Box2
Box1 < Box2
Box1 != Box2
Box3 == Box4

単項演算子のオーバーロード例

public static Box operator-(Box b) {  // 単項マイナス
    return new Box {
        length = -b.length,
        breadth = -b.breadth,
        height = -b.height
    };
}

public static Box operator++(Box b) {  // インクリメント
    b.length++; b.breadth++; b.height++;
    return b;
}

public static bool operator true(Box b) {  // true/false演算子(&&/||制御用)
    return b.length > 0 || b.breadth > 0 || b.height > 0;
}
public static bool operator false(Box b) => !b;

暗黙的/明示的変換演算子

型変換も演算子オーバーロードとして定義できます。

class Rational {
    public int Numerator { get; }
    public int Denominator { get; }
    
    // 暗黙的変換(int → Rational)
    public static implicit operator Rational(int value) 
        => new Rational(value, 1);
    
    // 明示的変換(Rational → double)
    public static explicit operator double(Rational r) 
        => (double)r.Numerator / r.Denominator;
}

ベストプラクティス

C言語

  1. オペレーター関与維持管理:メリットは隠れたコストを上回るか?
  2. DIY Wall-E 風 Raspberry Pi CD ボックスロボット
  3. C#演算子完全ガイド:C#における演算子の包括的解説
  4. C# 三項演算子:条件式を簡潔に書くためのガイド
  5. C#メソッドオーバーロード完全ガイド:概念、例、ベストプラクティス
  6. C#コンストラクタオーバーロード完全ガイド:柔軟なクラス設計
  7. C++演算子オーバーロード:コード例付き実践ガイド
  8. C++オーバーロード完全マスター:関数と演算子のオーバーロード
  9. MATLAB基礎マスター:必須構文とコマンド完全ガイド
  10. Python演算子オーバーロード完全ガイド:__add__、__lt__など特殊メソッドでOOP設計を強化
  11. Java instanceof演算子完全ガイド:基本から継承・インターフェースまで