戻り値をオーバーロードするC ++演算子の定数の正確さ
-
08-07-2019 - |
質問
なぜfooの代わりにc ++のバイナリ演算子からconst fooを返すように言われたのか少し混乱しています。
Bruce Eckelの「Thinking in C ++」を読んでおり、演算子のオーバーロードに関する章で、「オーバーロードするバイナリ演算子の」戻り値をconstにすることで、その戻り値に対してconstメンバー関数のみを呼び出すことができると述べます。失われる可能性が最も高いオブジェクトに潜在的に価値のある情報を保存することを防ぐため、これはconst-correctです。
ただし、constを返すプラス演算子とプレフィックスインクリメント演算子がある場合、このコードは無効です:
class Integer{
int i;
public:
Integer(int ii): i(ii){ }
Integer(Integer&);
const Integer operator+();
Integer operator++();
};
int main(){
Integer a(0);
Integer b(1);
Integer c( ++(a + b));
}
この種の割り当てを許可するには、+演算子に非const値を返すのは意味がありませんか?これはconst_castsを追加することで実行できますが、かなりかさばりませんか?
ありがとう!
解決
++ xと言うと、「xに1を追加し、結果をxに保存して、それが何であったかを教えてください」と言っています。これはプリインクリメント演算子です。しかし、++(a + b)では、どのようにして「結果をa + bに戻す」のでしょうか?
確かに、a + bの結果を現在保持しているテンポラリに結果を保存することができます。これはすぐに消えます。しかし、結果の保存場所を本当に気にしなかった場合、結果を追加するのではなく、なぜそれを増やしたのですか?
他のヒント
FYI、 ++(a + b)
は、POD( int
などの単純な古いデータ型)でも違法です。したがって、独自のクラス型にも許可しないことは理にかなっています。これを試してください:
int a = 1;
int b = 2;
int c = ++(a+b);
GCCは error:lvalue required as increment operand
を返します。
あなたの場合、コピーコンストラクタに const Integer
引数を取り、代わりに次のように Integer c
を作成させることが望ましいでしょう:
Integer c(a + b + Integer(1));
コピーコンストラクターは通常 const 参照を取り、その問題を解決します。
(非constコピーctorを持っていることは、リソースの転送を意味します。これは時々役立つことがありますが、すべての状況の99%で、それは必要ありません)
OPの例は、加算演算子が、参照を返す他のバイナリ演算子(代入演算子など)で置き換えられている場合、質問に適していると思います:
Integer c( ++(a = b));
ここで、代入演算子にconst参照または非const参照を返すようにすべきかどうか疑問に思いました。 一部のチュートリアル 「Thinking in C ++」のアドバイスに反して、非constバージョンを使用してください。また、他の参考文献はその背後にある理由を示しています。
返される参照がconstとして宣言されていないことに注意してください。次のようなクレイジーなものを書くことができるため、これは少し混乱する可能性があります。
MyClass a、b、c;
...
(a = b)= c; //何??
一見すると、operator =がconst参照を返すことにより、このような状況を防ぐことができます。ただし、このようなステートメントはプリミティブ型で機能します。さらに悪いことに、一部のツールは実際にこの動作に依存しています。したがって、operator =から非const参照を返すことが重要です。経験則では、「intに十分であれば、ユーザー定義のデータ型に十分です」です。