2016-05-18 5 views
2

私はコンストラクタと代入演算子の使い方を理解しようとしています。私はこのプログラムでこれを試しています。なぜオーバーロードされた代入演算子を呼び出すときにコピーコンストラクタが呼び出されますか?

#include <iostream> 
using namespace std; 

class myclass { 
    int x; 
public: 
    myclass (int p) { 
     cout << "calling constructor" << endl; 
     x = p; 
    } 
    myclass() { 
     cout << "calling constructor with no arguments" << endl; 
     x = 0; 
    } 
    myclass (myclass &t) { 
     cout << "calling copy constructor" << endl; 
     x = t.x; 
    } 

    myclass operator=(myclass &t) { 
     cout << "calling assignment operator" << endl; 
     x = t.x; 
     return *this; 
    } 

    void show() { 
     cout << "val = " << x << endl; 
    } 
}; 


int main() { 
    myclass a1; 
    a1.show(); 
    myclass a2 = a1; 
    a2.show(); 
    myclass a3(a2); 
    a3.show(); 
    myclass a4(200); 
    a2 = a4; 
    a2.show(); 
    return 0; 
} 

出力:

calling constructor with no arguments // call 1 
val = 0 
calling copy constructor // call 2 
val = 0 
calling copy constructor // call 3 
val = 0 
calling constructor // call 4 
calling assignment operator // call 5 
calling copy constructor // call 6 i am not able to understand this print line 
val = 200 

コール1、MyClassのA1から行われます。

コール2は、myclass a2 = a1から実行されます。

コール3は、myclass a3(a2)から実行されます。

コール4は、myclass a4(200)から実行されます。

コール5は、a2 = a4から行われます。

しかし、私は、コール6は、それは命令から呼び出されたどこから来ている取得することはできませんよ。

a2 = a4; 

しかし、それはどのようにコンストラクタをコピーするコールを与えるのだろうか?

ヘルプ/ポインタは大きな助けになるでしょう。私はcからcppに潜入していますので、私に同行してください。

+2

あなたは= 'だけでなく'オーバーロードしています。それはそこから来ている。 –

+0

はい、printステートメント "呼び出し代入演算子"が起きています。これは呼び出し5です。しかし、なぜ6を呼び出しますか?どこから呼び出されたのでしょうか? –

+0

コピー代入演算子は参照を返す必要があります。 –

答えて

2
myclass operator=(myclass &t) { 
    cout << "calling assignment operator" << endl; 
    x = t.x; 
    return *this; 
} 

上記の関数は値によって戻ります。 コピーコンストラクタが呼び出された場合の値の1つが戻り値です。 AFAIKでは、コンパイラが戻り値の最適化を実装しているため、これは必ずしも真ではありません(コピーコンストラクタを呼び出すことによって返される)。

+0

はい。ありがとう。私はこれが2番目の呼び出しの理由だと思う。私は参照の代わりに値を保持しています。 Slardar Zhang –

+0

これもRVOの実行可能なシナリオではありません。 –

+0

@LightnessRacesinOrbit。私はRVOによく精通していません。あなたがこれについていくつかの光を放つことができれば素晴らしいでしょう。 –

2

(あなたはコンストラクタと代入演算子は少し不正な形式にコピーします。彼らは、引数としてconst参照を取るべき、と代入演算子は参照ない値を返すべき)。

myclass a2 = a1;には、a2はまだ存在しません。そのため、コピーコンストラクタはa1を使用してa2を作成するために呼び出されます。

しかしa2 = a4

a2はすでに存在しているので、代入演算子は a4から a2割り当てる に使用されます。

ルールは本質的に次のとおりです。オブジェクトが存在しない場合は、構築する必要があります。あなたの観測された出力はこのルールを適用することで説明できます。その後、

myclass& operator=(myclass &t) 

+0

ありがとう、しかし、私はa2 = a4と言っています。これは、コンストラクタをコピーするのではなく、オーバーロードされた演算子関数のみを呼び出す必要があります。しかし、あなたが出力呼び出しを見るならば、5は同じものを表示しています。しかし、どこからコール6が呼び出されているのですか?私と一緒に抱きしめてください。 –

+2

'return * this' –

+0

オペレータの過負荷が不正です。答えの始めに私のコメントを見てください。 – Bathsheba

1

変更には:

calling constructor with no arguments 
val = 0 
calling copy constructor 
val = 0 
calling copy constructor 
val = 0 
calling constructor 
calling assignment operator 
val = 200 

あなたが値で返す場合は、コピーのctorが呼び出されます。 copy ctorを呼び出さないように、参照渡しに戻ります。

1

代理店オペレーターはを返します。返されたときに別のコピーが作成されます。

これは、6番目の呼び出しが行われる場所です。

あなたreturn *this、あなたが本当に*thisを返さないときように、一般的には、代入演算子は、代わりに参照を返します。

myclass& operator=(myclass &t) { 
// ^
関連する問題