質問
C ++の数値のようなクラスに算術演算子のオーバーロードを実装するための標準的なパターンまたは推奨パターンはありますか?
C ++ FAQから、ほとんどの問題を回避する例外安全な代入演算子があります:
class NumberImpl;
class Number {
NumberImpl *Impl;
...
};
Number& Number::operator=(const Number &rhs)
{
NumberImpl* tmp = new NumberImpl(*rhs.Impl);
delete Impl;
Impl = tmp;
return *this;
}
ただし、他の演算子(+、+ =など)については、組み込み型の演算子のように動作させる以外、ほとんどアドバイスは与えられません。
これらを定義する標準的な方法はありますか?これは私が思いついたものです-私が見ない落とし穴がありますか?
// Member operator
Number& Number::operator+= (const Number &rhs)
{
Impl->Value += rhs.Impl->Value; // Obviously this is more complicated
return *this;
}
// Non-member non-friend addition operator
Number operator+(Number lhs, const Number &rhs)
{
return lhs += rhs;
}
解決
Bjarne Stroustrupの本" C ++プログラミング言語&quot ;、第11章(オペレーターのオーバーロードに特化したもの)で、彼は複素数型のクラスを作成します(セクション11.3)。
このセクションで気づいたことの1つは、彼が混合型操作を実装していることです。これは、おそらく数値クラスで期待されています。
一般に、あなたが持っているものは見栄えが良い。
他のヒント
演算子を記述する際に考慮すべき大きなことは、メンバー演算子が左側のパラメーターで変換を受けないことです:
struct example {
example(int);
example operator + (example);
};
void foo() {
example e(3), f(6);
e + 4; // okay: right operand is implicitly converted to example
e + f; // okay: no conversions needed.
6 + e; // BAD: no matching call.
}
これは、変換がメンバー関数の this
に適用されないためであり、これは演算子にも拡張されます。演算子が代わりにグローバル名前空間で example operator +(example、example)
である場合、コンパイルされます(またはpass-by-const-refが使用された場合)。
その結果、 +
や-
などの対称演算子は一般に非メンバーとして実装されますが、 + =
などの複合代入演算子はおよび-=
はメンバーとして実装されます(データも変更するため、メンバーである必要があります)。また、コードの重複を避けたいので、対称演算子は複合割り当ての観点から実装できます(コード例のように、慣例では関数内に一時的なものを作成することを推奨しています)。
慣例では、 operator + =(const T&)
および operator-(const T&)
を operator + =(const T&)
および operator-=(const T&)
。プリミティブ型の追加と削除が理にかなっている場合は、プリミティブ型からオブジェクトを構築するコンストラクターを作成する必要があります。コンパイラーは暗黙的に適切なコンストラクターを呼び出すため、オーバーロードされた演算子はプリミティブ型でも機能します。
自分で言ったように、必要のない関数にはアクセス権を与えないでください。しかし、上記の operator +(Number、const Number&)
のコードでは、個人的に両方のパラメーターをconst参照にし、tempを使用します。あなたの質問の下のコメント者がこれを見逃したのは驚くことではないと思います。正当な理由がない限り、驚きやトリックを避け、可能な限り自明になります。
コードを他の数値型、たとえば std :: complex
と統合する場合は、循環変換に注意してください。つまり、 OtherNumeric
が Numeric
を受け取るコンストラクタを提供する場合、 Numeric
に operator OtherNumeric()
を指定しないでください。パラメータ。
演算子= X
に関して演算子Xを記述するのが伝統的です
また、標準的な演算子へのすべてのパラメータはconstです
// Member operator
// This was OK
Number& Number::operator+= (Number const& rhs)
{
Impl->Value += rhs.Impl->Value; // Obviously this is more complicated
return *this;
}
// Non-member non-friend addition operator
Number operator+(Number const& lhs,Number const& rhs)
{
// This I would set the lhs side to const.
// Make a copy into result.
// Then use += add the rhs
Number result(lhs);
return result += rhs;
}
代入演算子に言及します。
ただし、コピーコンストラクターについては言及しませんでした。あなたのクラスはRAWポインタの所有権を持っているので、これも定義することを期待します。代入演算子は、従来、コピーコンストラクターの観点から記述されています。