私は間の違いについて少し混乱しています
Type operator + (const Type &type);
Type &operator += (const Type &type);
そして
friend Type operator + (const Type &type1, const Type &type2);
friend Type &operator += (const Type &type1, const Type &type2);
どちらの方法が好ましいですか、それらはどのように見え、いつどちらを使用する必要がありますか?
演算子の最初の形式は、クラスType
内で定義するものです。
演算子の2番目の形式は、クラスType
と同じ名前空間で独立した関数として定義するものです。
独立した関数を定義することは非常に良い考えです。なぜなら、それらのオペランドは暗黙の変換に参加できるからです。
このクラスを想定します。
_class Type {
public:
Type(int foo) { }
// Added the const qualifier as an update: see end of answer
Type operator + (const Type& type) const { return *this; }
};
_
次に、次のように書くことができます。
_Type a = Type(1) + Type(2); // OK
Type b = Type(1) + 2; // Also OK: conversion of int(2) to Type
_
しかし、あなたは書くことができませんでした:
_Type c = 1 + Type(2); // DOES NOT COMPILE
_
_operator+
_を無料の関数として使用すると、最後のケースも可能になります。
ただし、演算子の2番目の形式が間違っているのは、オペランドのプライベートメンバーを直接微調整することによって加算を実行することです(そうでなければ、フレンドである必要はないと思います)。 notはそれを行うべきではありません:代わりに、演算子もクラス内で定義されるべきであり、独立した関数はそれらを呼び出すべきです。
それがどうなるかを見るために、教祖のサービスを求めましょう: http://www.gotw.ca/gotw/004.htm 。最後にスクロールして、独立した機能を実装する方法を確認します。
更新:
James McNellisが彼のコメントで述べているように、与えられた2つの形式にも別の違いがあります。最初のバージョンでは、左側がconst-qualifiedではありません。 _operator+
_のオペランドは、実際には加算の一部として変更すべきではないため、常にconst-qualifyすることをお勧めします。私の例のクラスType
はこれを実行しますが、最初は実行しませんでした。
演算子_+
_および_+=
_を処理する最良の方法は次のとおりです。
operator+=
_をT& T::operator+=(const T&);
として定義します。これは、追加が実装される場所です。operator+
_をT T::operator+(const T&) const;
として定義します。この演算子は、前の演算子の観点から実装されます。T operator+(const T&, const T&);
を提供します。この関数は、メンバー_operator+
_を呼び出して作業を行います。手順2を省略して、無料の関数で_T::operator+=
_を直接呼び出すこともできますが、個人的な好みとして、すべての加算ロジックをクラス内に保持したいと思います。
C++ 03およびC++ 0x( [〜#〜] nrvo [〜#〜] およびmove-semantics)に関して、演算子を実装する適切な方法は次のとおりです。
struct foo
{
// mutates left-operand => member-function
foo& operator+=(const foo& other)
{
x += other.x;
return *this;
}
int x;
};
// non-mutating => non-member function
foo operator+(foo first, // parameter as value, move-construct (or elide)
const foo& second)
{
first += second; // implement in terms of mutating operator
return first; // NRVO (or move-construct)
}
上記を次のように組み合わせたくなることに注意してください。
foo operator+(foo first, const foo& second)
{
return first += second;
}
しかし、(私のテストでは)コンパイラがNRVOを有効にしない(またはセマンティクスを移動する)ことがあります。これは、(ミューテーション演算子をインライン化するまで)first += second
はfirst
と同じです。より簡単で安全なのは、それを分割することです。
friend
指定子は、宣言されているものがクラスのメンバーではないが、その仕事をするためにクラスのインスタンスのプライベートメンバーにアクセスする必要がある場合に使用されます。
演算子がクラス自体で定義される場合は、最初の方法を使用してください。スタンドアロン関数の場合は、2番目の関数を使用します。