2

オーバーロードについて 2 つの質問があります。

1-オーバーロード演算子を非メンバー関数にすることがあるのはなぜですか?

friend Class operator-(const Class &rhs);

2-違いは何ですか

Class operator+(const Class &c1, const Class &c2);

Class operator+(const Class &rhs);

2 つのオブジェクトを追加したいC3 = C1 + C2場合

どんな助けでも大歓迎です...

4

3 に答える 3

4

二項演算子をメンバー関数としてオーバーロードすると、最終的に非対称になります。左のオペランドは、演算子がオーバーロードされる正確な型である必要がありますが、右のオペランドは、正しい型に変換できるものであれば何でもかまいません。

非メンバー関数で演算子をオーバーロードすると、両方のオペランドを変換して正しい型を取得できます。

2番目のポイントとして持っているものは、同じポイントの具体的な例のように見えますが、実際にはまったく別のものではありません. これが私が話していることの具体的な例です:

class Integer {
    int val;
public:
    Integer(int i) : val(i) {}
    operator int() { return val; }

    // Integer operator+(Integer const &other) const { return Integer(val + other.val); }

    friend Integer operator+(Integer const &a, Integer const &b) { 
        return Integer(a.val + b.val);
    }
};


int main() { 
    Integer x(1);

    Integer y = x + 2; // works with either operator overload because x is already an Integer

    Integer z = 2 + x; // works with global overload, but not member overload because 2 isn't an Integer, but can be converted to an Integer.
    return 0;
}

friendまた、関数の定義が のクラス定義内にある場合でもInteger、それがフレンドとして宣言されているという事実は、それがメンバー関数ではないことを意味することに注意してください。それを宣言するfriendと、メンバーではなくグローバル関数になります。

結論: このようなオーバーロードは、通常、メンバー関数ではなく、フリー関数として実行する必要があります。正しく (大幅に) 動作するオペレーターをユーザーに提供することは、「よりオブジェクト指向」などの理論的な考慮事項よりも重要です。オペレーターの実装を仮想化する必要がある場合など、必要に応じて、実際の作業を行う (おそらく仮想の) メンバー関数を提供する 2 ステップ バージョンを実行できますが、オーバーロード自体は自由な関数であり、左オペランドでそのメンバー関数を呼び出します。これのかなり一般的な例の 1 つはoperator<<、階層のオーバーロードです。

class base { 
    int x;
public:
    std::ostream &write(std::ostream &os) const { 
        return os << x;
    }
};

class derived : public base { 
    int y;
public:
    std::ostream &write(std::ostream &os) const { 
        return (base::write(os) << y);
    }
};

std::ostream &operator<<(std::ostream &os, base const &b) {
    return b.write(os);
}

これは、取得するためのオペレーターの通常の特性をあきらめることなく、ポリモーフィックな実装 (および必要に応じて基本クラスの保護されたメンバーへのアクセス) の両方をサポートします。

二項演算子をフリー関数としてオーバーロードする主な例外は、代入演算子 ( operator=operator+=operator-=などoperator*=) です。変換により一時オブジェクトが生成されますが、これに代入することはできません。そのため、この特定のケースでは、オーバーロードは (実際にはそうである必要があります) 代わりにメンバー関数にする必要があります。

于 2012-07-27T04:07:55.513 に答える
2

1-オーバーロード演算子を非メンバー関数にすることがあるのはなぜですか?

それは選択の問題です。operator +/-クラスメンバーにするか、フリーfriend関数にすることができます。
無料の関数の場合、指定した構文operator -は間違っていfriendます.2つの引数を取る必要があります(例と同様operator +)。

2-違いは何ですか

前に述べたように、それは単なる構文の違いです。1 つ目は無料のfriend関数で、2 つ目はclassメンバーです。

classそれに加えて、メンバーメソッドとして演算子を保持することは、フリー関数と比較して優れていると私は信じています。

  1. 該当する場合、メンバー メソッドprotectedは基本クラスのメンバーにアクセスできますが、friend関数はアクセスできません。
  2. クラスに関連するメソッドを関連付けるため、メンバーメソッドはよりオブジェクト指向のアプローチです
于 2012-07-27T03:55:15.817 に答える
0

オーバーロードされたオペレーターを友達にすることは、より良いオプションです。

class Comples
{
   public:
      Complex(float real, float imaginary);
      friend operator+ (const Complex &rhs);
   ...
};

オペレーターを友達にすることで、次のことができます

Complex result1 = 5.0 + Comples(3.0, 2.0);

Complex result1 = Comples(3.0, 2.0) + 5.0;

これは、追加の共同性プロパティの規則に従います。オーバーロードされた演算子がメンバー関数である場合、これは実現できません。これはComplex、この場合、コンパイラが必要に応じてオブジェクトを暗黙的に作成できるためです。したがって、友人である場合の加算演算子は、数学における加算の通常の概念に従って動作します。

于 2012-07-27T04:08:22.317 に答える