2016-12-11 20 views
3

演算子がオーバーロードされていないクラスの+、 - 、*、/演算子はどのように定義されますか?私は次のクラスを実装しました。オペレータに過負荷をかけることなく、上記の演算子が動作し、実装する方法で動作します。C#のデフォルトの算術演算子

class Number 
{ 
    private float mDecimal; 
    public float Decimal 
    { 
     get { return mDecimal; } 
    } 

    private int mOrder; 
    public int Order 
    { 
     get { return mOrder; } 
    } 

    public Number(float dec, int pow) 
    { 
     mDecimal = dec; 
     mOrder = pow; 
    } 

    public Number Power(Number number) 
    { 
     throw new NotImplementedException(); 
    } 

    public static implicit operator Number(float num) 
    { 
     int pow = 0; 
     while (num > 1000) 
     { 
      num *= 0.1f; 
      ++pow; 
     } 

     return new Number(num, pow); 
    } 

    public static implicit operator float(Number num) 
    { 
     float result = num.mDecimal; 
     for (int i = 0; i < num.mOrder; ++i) 
      result *= 10; 
     return result; 
    } 
} 

今すぐアカウントに使用コードのこの部分を取る:は15と評価さ

Number n1 = 5; 
Number n2 = 10; 
Number n3 = n1 + n2; 

N3 は、ここでは、コードです!これは他の演算子でも起こります!次のように

+5

'implicit operator float'を定義しているので、' + '演算子は暗黙的に値を' Number'から 'float'(' System.Single')に暗黙的に変換し、加算を実行してから、 。 – Dai

+1

暗黙の演算子にブレークポイントを配置しようとしたことはありませんでした。 – Andrew

+0

@Andrew私はC#を初めて使っています。私の背景は暗黙のうちにこの種の状況を処理しないC++です。だから型を知らなくても、** Number **は浮動小数点に変換できるので、浮動小数点数を使用しますか?別のカスタムクラスのために他の変換演算子を配置しましたが、浮動小数点演算子を再度使用します。コンパイラは算術演算子を提供するためにどのような変換を行うかをどのように選択しますか? – Klaus

答えて

6

n3 = n1 + n2が評価される:

  1. まず、候補演算子のリストは、任意のユーザ定義のオーバーロード(ECMA-334, section 14.2.4)を含め、決定されます。何も適用されないので、候補演算子のセットは事前定義された2項演算子+になります。自分で定義した場合operator+(Number, Number)これは選択された場所です。
  2. これで、+の実装(14.4.2項)を使用するかどうかを決定するために、オーバーロードの問題が発生しました(おそらく、これを実装する必要があります)。これはおそらくC#仕様の最も複雑な部分ですが、深く掘り下げる必要はありません。適切な過負荷を選択する際に暗黙的な変換が適用されるという知識が必要です(14.4.2.1)。正確なルールについては、ユーザー定義のコンバージョンについてのセクション13.4も参照する必要があります。
  3. 言語では、組み込みの変換を使用していても、ユーザー定義の暗黙的な変換が処理されます。この場合、Numberからfloatへの暗黙的な変換が行われるため、暗黙の変換を伴うfloat operator +(float, float)が残っているため、+の残りの唯一のオーバーロード候補が呼び出されます。
  4. 結果としてfloatは、他の演算子を使用して暗黙的にNumberに変換されます。これがなくても、まだfloatが追加されますが、結果は変換されないことに注意してください。コンパイラは実際には演算子を "持ち上げる"わけではありませんが、効果はほとんど同じです(値型のnull可能なバージョンでは浮動しますが、別の話です)。

暗黙的な変換を持つタイプを混在させると、物事が複雑になることがあります。オーバーロードの解決はRight Thingを実行するのが非常に難しく、ルールは明白ですが、変換が関係するときを見るのは難しいので、暗黙的な変換演算子をあまり使わないでください。明示的な変換にはもう少しキーストロークが必要ですが、どのオペレータが呼び出されるのかがわかりやすくなります。最初にタイプを開発していて、まだ実装されていない演算子を確認できるようにするためには、これは確かに当てはまります(パフォーマンスや精度の理由から必要です)。

+0

これは、複数の方法で、恩恵を受ける回答のタイプとまったく同じです。 – Klaus