C++での演算子のオーバーロードの戻り値について質問があります。一般的に、2つのケースが見つかりました。1つは値による戻り、もう1つは参照による戻りです。それで、その下のルールは何ですか?特に、cout<<x<<y
のように、演算子を継続的に使用できる場合。
たとえば、+操作「string +(string)」を実装する場合。 refまたはvalで、戻り値をどのように返しますか。
いくつかの演算子は値で、いくつかは参照で返します。一般に、結果が新しい値(+、-など)の演算子は値ごとに新しい値を返す必要があり、結果が既存の値であるが変更された演算子(<<、>>、+など)を返す必要があります=、-=など)、変更された値への参照を返す必要があります。
たとえば、cout
はstd::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
と同等です。
逆に、「文字列+文字列」の場合、結果は新しい文字列(両方の元の文字列は変更されない)であるため、値で返す必要があります(そうでない場合、未定義の動作である一時への参照を返します)。
文字列に関する質問への回答を試みるために、文字列の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;
}
演算子のオーバーロードを組み込み演算子のように動作させる場合、ルールは非常に簡単です。標準は、組み込み演算子の動作を正確に定義し、組み込みの結果がrvalue
かlvalue
かを示します。
使用すべきルールは次のとおりです。
rvalue
を返す場合、オーバーロードは参照を返す必要がありますlvalue
を返す場合、オーバーロードは値を返す必要がありますただし、ビルトインと同じ種類の結果を返すためにオーバーロードは必要ありませんが、それ以外の理由がない限り、これを行う必要があります。
たとえば、KennyTMは別の回答へのコメントで、ストリームが<<
および>>
演算子は、左側のオペランドへの参照を返しますが、これは組み込みの動作ではありません。しかし、ストリームインターフェイスの設計者がこれを行ったため、ストリームI/Oをチェーン化できました。
演算子によっては、値で返す必要があります。
ただし、operator + =のように両方を使用できる場合は、次のことを検討できます。
通常、=
や+=
など、操作対象の値を変更する操作で参照によって戻ります。他のすべての操作は値によって返されます。
ただし、これは経験則です。どちらの方法でもオペレーターを設計できます。