2011-10-22 16 views
0

私は、3つの浮動小数点、x y z、いくつかの関数とオーバーロードされた演算子を保持するPointクラスを作成しています。私は以下の形式で演算子をコード化しました:オペレータのオーバーロードとVS2010でのLNK2019のエラー

inline Point Point::operator+ (Point point) 
{ 
    return Point(x + point.x, y + point.y, z + point.z); 
} 

inline void Point::operator+= (Point point) 
{ 
    x += point.x; 
    y += point.y; 
    z += point.z; 
} 

これは正しい演算子ですか?私はそれを試して、それが動作しますが、私はそういう別のフォームを見た:

inline Point& Point::operator+ (Point& point) 
{ 
    return Point(x + point.x, y + point.y, z + point.z); 
} 

inline Point& Point::operator+= (Point& point) 
{ 
    x += point.x; 
    y += point.y; 
    z += point.z; 
     return *this; 
} 

2つのフォームの違いは何ですか?

また、私はPoint.cppファイル内の演算子を使用できますが、Main.cppで使用しようとすると、未解決の外部シンボルに対してlnk2019エラーが発生します。奇妙なことに、私の関数は定義ファイルの外で動作します。これらの演算子を定義したファイルの外で動作させるには、何が欠けていますか?

+0

リンクエラーを回避するには、インラインで宣言しないでください。私は実際にそれが問題の原因であるとは思わないでしょうが。 –

答えて

3

最初のオペレータは、既存のもの(一般的な経験則)を変更新しいオブジェクトを構築しないように除外するので、それは参照を返すべきではない

inline Point Point::operator+ (const Point &point) const 
{ 
    return Point(x + point.x, y + point.y, z + point.z); 
} 

であるべきです。その呼び出された点が変更されてはならないため、関数にconstが追加されます。それが参照を返す必要がありますので、既存のポイントを修正することになっているので、引数が追加される点を基準不要なコピーができなくなりますので

は、第1には、

inline Point& Point::operator+= (const Point& point) 
{ 
    x += point.x; 
    y += point.y; 
    z += point.z; 
    return *this; 
} 

でなければなりません。 constは変更されるべきではないので、引数に追加されます。関数自身はポイント自体を変更する必要があるため、関数自体はconstではありません。

リンカーエラーはインラインのためです。ヘッダーファイルに完全な実装を提供するか、インラインを削除してください。

+0

'operator +'の戻り値に 'const'を加えてください。 –

+0

@EricZ:なぜですか? 'Point result = p1 + p2; 'のようなものは動作しません – Dani

+0

間違っています。 'Point result = p1 + p2'は値でコピーされて動作します。 'const'は' p1 + p2 = result'を防ぎ、 'p1 + p2'の非constメンバー関数を呼び出すためのものです。 –

2
inline Point& Point::operator+ (Point& point) 
{ 
    return Point(x + point.x, y + point.y, z + point.z); 
} 

これは間違っていますが、関数が返されたときに一時的に存在しなくなった参照を返します。あなたが十分に幸運であれば、それはセグメンテーションにつながるでしょう。ほとんどのコンパイラは、実行しようとすると警告を出します。理想的には、この演算子を自由な関数として記述し、メンバーoperator+=の形で実装します。

inline Point& Point::operator+= (Point& point) 
{ 
    x += point.x; 
    y += point.y; 
    z += point.z; 
     return *this; 
} 

これは、あなたがそうでなければ、あなたが一時にそれを使用することはできません、const参照としてpointを服用しなければならないことを除いて、ほとんど好ましい方法です。連鎖演算子を許可するのは、自身への参照を返すことです。一般的に、疑わしいときはintとして、intはそうすると言います。要約

、「cannonical」の実装は次のようになります持っoperator+はフリー機能することが

inline Point& Point::operator+=(Point const& point) 
{ 
    x += point.x; 
    y += point.y; 
    z += point.z; 
    return *this; 
} 

inline Point const operator+(Point left, Point const& right) 
{ 
    return left += right; 
} 

Pointへの変換は、両方のオペランドだけでなく、右の1で発生することができます。 operator+=で便利に実装されています。左の引数は、変更可能な一時的なコピーを持つために値で取り込まれ、それに正しい引数を追加することによって行います。 operator+=は参照を返しますので、関数の結果としてコピーされる値を提供するためにこのような戻り値を使用します。

+0

'Point'クラスは変換コンストラクタを持っていないと思われるので、メンバーバージョンの' operator + 'が好きです。また、一貫性のあるw/build-in型となるように 'const point'を返さなければなりません。 –

+0

@Eric Z: 'const'を追加しました。 'Point'クラスに変換コンストラクタがない場合でも、他のクラスが変換演算子を提供することを常に決める機会があります。また、クラス自体から独立しており、クラスインタフェースの観点から表現すると、それをデカップリングして自由な関数にする方がよい。 –

+0

+1:ああ。その場合、 'operator +'は通信可能でなければならないので、非メンバ関数として置くことは理にかなっています。 –

関連する問題