web-dev-qa-db-ja.com

演算子のオーバーロード:メンバー関数対非メンバー関数?

メンバー関数として宣言されたオーバーロードされた演算子はasymmetricであり、パラメーターは1つしか持つことができず、自動的に渡されるパラメーターはthisポインターであるためです。したがって、それらを比較する標準は存在しません。一方、friendとして宣言されているオーバーロードされた演算子はsymmetricです。これは、同じ型の2つの引数を渡すため、比較できるためです。

私の質問は、ポインターの左辺値をまだ参照と比較できるのに、なぜ友達が好まれるのかということです。 (非対称バージョンを使用すると対称と同じ結果が得られます)STLアルゴリズムが対称バージョンのみを使用するのはなぜですか?

105
badmaash

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

しかし、第1オペランドがクラスではない場合はどうでしょうか? 最初のオペランドがクラス型ではなく、doubleと言う演算子をオーバーロードしたい場合、大きな問題があります。10.0 + s2のように書きます。ただし、s1 + 10.0などの式の演算子オーバーロードメンバー関数を作成できます。

このordering問題を解決するために、friendメンバーにアクセスする必要がある場合、演算子のオーバーロード関数をprivateとして定義します。 プライベートメンバーにアクセスする必要がある場合にのみfriendにしてください。それ以外の場合は単純に non-memberfunction toimproveencapsulation!

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
}

これらを読んでください:
オペランドの順序に関するわずかな問題
非メンバー関数がカプセル化を改善する方法

134
Nawaz

friend演算子オーバーロードとメンバー関数演算子オーバーロードは、global演算子オーバーロードとメンバー関数演算子オーバーロードの間にあるため、必ずしも区別されません。

global演算子のオーバーロードを好む理由の1つは、クラスタイプがrightに表示される式を許可する場合です。 二項演算子の手側。例えば:

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

これは、グローバル演算子のオーバーロードがある場合にのみ機能します

Foo演算子+(int x、const Foo&f);

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

とにかく、Fooに次のようなメンバー関数演算子のオーバーロードがある場合:

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

...その後、プラス演算子のleftFooインスタンスが表示される式のみを使用できます。

18
Charles Salvia