81

メンバー関数として宣言されたオーバーロードされた演算子は、1つのパラメーターしか持たず、自動的に渡されるもう1つのパラメーターが 'this'ポインターであるため非対称です。したがって、それらを比較する標準は存在しません。一方、同じ型の2つの引数を渡すため、友人として宣言されたオーバーロードされた演算子は対称です。したがって、それらを比較することができます。 私の質問は、私はまだポインタのlvalueを参照と比較することができますが、なぜ友人が優先されるのですか? (非対称バージョンを使用すると対称と同じ結果が得られます) STLアルゴリズムは対称バージョンのみを使用するのはなぜですか?演算子のオーバーロード:メンバ関数と非メンバ関数の比較?

+9

あなたの質問は唯一の二項演算子について実際にあります。すべてのオーバーロードされた演算子が単一のパラメータに制限されているわけではありません。 ()演算子は任意の数のパラメータを取ることができます。一方、単項演算子はパラメータを持つことはできません。 –

+1

http://stackoverflow.com/a/4421729/103167 –

+2

[C++ FAQ:オペレータのオーバーロード](http://stackoverflow.com/questions/4421706/operator-overloading) –

答えて

101

演算子オーバーロードされた関数をメンバー関数として定義すると、コンパイラはs1 + s2のような式をs1.operator+(s2)に変換します。 つまり、演算子のオーバーロードされたメンバー関数は、最初のオペランドで呼び出されます。これはメンバー関数の仕組みです!

しかし、最初のオペランドがクラスでない場合はどうなりますか? 最初のオペランドがクラス型ではなく、むしろdoubleという演算子をオーバーロードしたい場合、大きな問題があります。だからこのように書くことはできません10.0 + s2。しかし、s1 + 10.0のような式の演算子のオーバーロードされたメンバー関数を書くことができます。それはprivateメンバーにアクセスする必要がある場合

この 問題を注文解決するために、我々は friendように、オペレータオーバーロードされた関数を定義します。 プライベートメンバーにアクセスする必要がある場合のみfriendにしてください。それ以外の場合は単に ノンフレンドの非会員の機能に を改善するカプセル化!

class Sample 
{ 
public: 
    Sample operator + (const Sample& op2); //works with s1 + s2 
    Sample operator + (double op2); //works with s1 + 10.0 

    //Make it `friend` only when it needs to access private members. 
    //Otherwise simply make it **non-friend non-member** function. 
    friend Sample operator + (double op1, const Sample& op2); //works with 10.0 + s2 
} 

これらを読む:
A slight problem of ordering in operands
How Non-Member Functions Improve Encapsulation

+2

"プライベートメンバーにアクセスする必要がある場合にのみ、それを' friend'にしてください。アクセサーを書くのに飽きたときはどうですか? – badmaash

+4

@Abhi:あなたの選択を選んでください:改良されたカプセル化とレイジーな習慣! – Nawaz

+0

グローバルな 'operator +()'を単に 'return op2.operator +(op1);'にすることによって、 'friend'キーワードを避けることができなかったケース?どちらの場合でも、+はデフォルトで入力Sampleを変更しません。代わりに 'Sample'の新しい右辺値のインスタンスを返します。右は – matthias

14

グローバルオペレータのオーバーロードとメンバ関数演算子オーバーロードの間にあるように、それは必ずしもfriendオペレータのオーバーロードとメンバ関数演算子のオーバーロードとの間の区別はありません。あなたはクラス型は、二項演算子の手元側に現れる場所を表現できるようにしたい場合はグローバル演算子オーバーロードを好む

一つの理由です。例えば:

Foo f = 100; 
int x = 10; 
cout << x + f; 

Fooの演算子+(INT X、CONST Fooの& F)のグローバルオペレータ過負荷がある場合にのみ動作します。

グローバル演算子のオーバーロードは、必ずしもfriend関数である必要はありません。これは、Fooのプライベートメンバーにアクセスする必要がある場合にのみ必要ですが、必ずしもそうであるとは限りません。かかわらず

Fooだけのように、メンバー関数の演算子オーバーロードを持っていた場合:その後、我々は唯一のFooインスタンスはプラスのを残しに表示される場所の表現を持っていることができるだろう...

class Foo 
{ 
    ... 
    Foo operator + (int x); 
    ... 
}; 

オペレーター。

+1

で説明されている多くのトピックの1つです。メンバー関数とフレンド関数ではなくメンバ関数と非メンバ関数を区別するために、図1に示す。私たちは今日、「グローバルまたはネームスペースの範囲」と言います。 –

関連する問題