web-dev-qa-db-ja.com

C ++での演算子のオーバーロードの戻り値

C++での演算子のオーバーロードの戻り値について質問があります。一般的に、2つのケースが見つかりました。1つは値による戻り、もう1つは参照による戻りです。それで、その下のルールは何ですか?特に、cout<<x<<yのように、演算子を継続的に使用できる場合。

たとえば、+操作「string +(string)」を実装する場合。 refまたはvalで、戻り値をどのように返しますか。

45
skydoor

いくつかの演算子は値で、いくつかは参照で返します。一般に、結果が新しい値(+、-など)の演算子は値ごとに新しい値を返す必要があり、結果が既存の値であるが変更された演算子(<<、>>、+など)を返す必要があります=、-=など)、変更された値への参照を返す必要があります。

たとえば、coutstd::ostreamであり、ストリームへのデータの挿入は変更操作であるため、<<演算子を実装してostreamに挿入するには、演算子はこのように定義されます:

std::ostream& operator<< (std::ostream& lhs, const MyType& rhs)
{
  // Do whatever to put the contents of the rhs object into the lhs stream
  return lhs;
}

このように、cout << x << yのような複合ステートメントがある場合、サブ式cout << xが最初に評価され、次に式[result of cout << x ] << yが評価されます。 xの演算子<<coutへの参照を返すため、式[result of cout << x ] << yは、予想どおりcout << yと同等です。

逆に、「文字列+文字列」の場合、結果は新しい文字列(両方の元の文字列は変更されない)であるため、値で返す必要があります(そうでない場合、未定義の動作である一時への参照を返します)。

67
Tyler McHenry

文字列に関する質問への回答を試みるために、文字列のoperator +()はほとんどの場合、自由な(非メンバー)関数として実装されるため、どちらのパラメーターでも暗黙的な変換を実行できます。それはあなたが次のようなことを言うことができるようにです:

string s1 = "bar";
string s2 = "foo" + s1;

それを考えると、どちらのパラメーターも変更できないことがわかるので、次のように宣言する必要があります。

RETURN_TYPE operator +( const string & a, const string & b );

現時点ではRETURN_TYPEを無視します。どちらのパラメーターも返せないため(変更できないため)、実装では新しい連結値を作成する必要があります。

RETURN_TYPE operator +( const string & a, const string & b ) {
    string newval = a;
    newval += b;    // a common implementation
    return newval;
}

RETURN_TYPEを参照にすると、ローカルオブジェクトへの参照が返されます。これは、ローカルオブジェクトが関数の外部に存在しないため、よく知られているno-noです。したがって、唯一の選択肢は、値、つまりコピーを返すことです:

string operator +( const string & a, const string & b ) {
    string newval = a;
    newval += b;    // a common implementation
    return newval;
}
12
anon

演算子のオーバーロードを組み込み演算子のように動作させる場合、ルールは非常に簡単です。標準は、組み込み演算子の動作を正確に定義し、組み込みの結果がrvaluelvalueかを示します。

使用すべきルールは次のとおりです。

  • 組み込み演算子がrvalueを返す場合、オーバーロードは参照を返す必要があります
  • 組み込みがlvalueを返す場合、オーバーロードは値を返す必要があります

ただし、ビルトインと同じ種類の結果を返すためにオーバーロードは必要ありませんが、それ以外の理由がない限り、これを行う必要があります。

たとえば、KennyTMは別の回答へのコメントで、ストリームが<<および>>演算子は、左側のオペランドへの参照を返しますが、これは組み込みの動作ではありません。しかし、ストリームインターフェイスの設計者がこれを行ったため、ストリームI/Oをチェーン化できました。

7
Michael Burr

演算子によっては、値で返す必要があります。

ただし、operator + =のように両方を使用できる場合は、次のことを検討できます。

  • オブジェクトが不変である場合は、おそらく値で返す方が良いでしょう。
  • オブジェクトが変更可能な場合は、おそらく参照によって返す方が良いでしょう。
3
Brian R. Bondy

通常、=+=など、操作対象の値を変更する操作で参照によって戻ります。他のすべての操作は値によって返されます。

ただし、これは経験則です。どちらの方法でもオペレーターを設計できます。

3
thebretness