1

コピーコンストラクターをよく理解しようとしていますが、コードのこの部分を見つけました。

 #include<iostream>
    using namespace std;
    class A1 {
        int data;
    public:
        A1(int i = 10) :
                data(i) {
            cout << "I am constructing an A1 with: " << i << endl;
        }
        A1(const A1& a1) :
                data(a1.data) {
            cout << "I am copy constructing an A1" << endl;
        }
        ~A1() {
            cout << "I am destroying an A1 with: " << data << endl;
        }
        void change() {
            data = data * 10;
        }
    };
    class A2 {
        int data;
    public:
        A2(int i = 20) :
                data(i) {
            cout << "I am constructing an A2 with: " << i << endl;
        }
        A2(const A2& a2) :
                data(a2.data) {
            cout << "I am copy constructing an A2" << endl;
        }
        ~A2() {
            cout << "I am destroying an A2 with: " << data << endl;
        }
        void change() {
            data = data * 20;
        }
    };
    class A3 {
    public:
        A3() {
            cout << "I am constructing an A3" << endl;
        }
        A3(const A3& a3) {
            cout << "I am copy constructing an A3" << endl;
        }
        ~A3() {
            cout << "I am destroying an A3" << endl;
        }
        void change() {
            cout << "Nothing to change" << endl;
        }
    };
    class A {
        A1 a1;
        A2 a2;
        A3 a3;
    public:
        A() {
            cout << "I am constructing an A" << endl;
        }
        A(const A& a) :
                a1(a.a1) {
            cout << "I am copy constructing an A" << endl;
        }
        ~A() {
            cout << "I am destroying an A" << endl;
        }
        A& operator=(const A& a) {
            cout << "I am performing a stupid assignment between As" << endl;
            if (this != &a)
                a1 = a.a1;
            return *this;
        }
        void change() {
            a1.change();
            a2.change();
            a3.change();
        }
    };
    class BigA {
        A data1;
        A& data2;
    public:
        BigA(A& a) :
                data1(a), data2(a) {
            cout << "I just constructed a BigA" << endl;
        }
        ~BigA() {
            cout << "I am destroying a BigA" << endl;
        }
        A get(int index) {
            if (index == 1)
                return data1;
            else
                return data2;
        }
    };
        BigA volta(BigA& biga)
     //BigA& volta(BigA& biga)
            {
        cout << "Volta ta data?" << endl;
        return biga;
    }
    int main() {
        A first;
        BigA biga(first);
        volta(biga).get(2).change();
        return 0;
    }

しかし、なぜこれらの結果が得られるのか理解できません。特に、コンストラクターではなく A1 と A のコピー コンストラクターが呼び出され、volta 関数が呼び出されたときにまったく得られない理由 (**** で囲まれた結果) :

I am constructing an A1 with: 10
I am constructing an A2 with: 20
I am constructing an A3
I am constructing an A
I am copy constructing an A1
I am constructing an A2 with: 20
I am constructing an A3
I am copy constructing an A
I just constructed a BigA
****
Volta ta data?
I am copy constructing an A1
I am constructing an A2 with: 20
I am constructing an A3
I am copy constructing an A
I am copy constructing an A1
I am constructing an A2 with: 20
I am constructing an A3
I am copy constructing an A
Nothing to change
I am destroying an A
I am destroying an A3
I am destroying an A2 with: 400
I am destroying an A1 with: 100
I am destroying a BigA
I am destroying an A
I am destroying an A3
I am destroying an A2 with: 20
I am destroying an A1 with: 10
****
I am destroying a BigA
I am destroying an A
I am destroying an A3
I am destroying an A2 with: 20
I am destroying an A1 with: 10
I am destroying an A
I am destroying an A3
I am destroying an A2 with: 20
I am destroying an A1 with: 10

EDIT_AssignmentOperatorQuery : この関数を BigA に追加すると

void change() {
    A& rdata1 = data1;
    A cdata2 = data2;
}

main から呼び出します:biga.change();デフォルトの代入演算子の代わりに、copy-constructor と constructor が呼び出されているのはなぜですか?

I am copy constructing an A1
I am constructing an A2 with: 20
I am constructing an A3
I am copy constructing an A

EDIT_AnsweringMyOwnQuery : これはコピー コンストラクターによる初期化であり、代入演算子による代入ではないことがわかりました。

4

1 に答える 1

1

それから始めましょう。

A first;

A オブジェクトを作成すると、そのフィールド (非静的メンバー) が初期化されます

"コンストラクターの関数本体を形成する複合ステートメントが実行を開始する前に、すべての直接ベース、仮想ベース、および非静的データ メンバーの初期化が終了します。"

I am constructing an A1 with: 10
I am constructing an A2 with: 20
I am constructing an A3

そして、パラメーターのないコンストラクターのバージョンが呼び出されています:

I am constructing an A

あなたが書くとき

BigA biga(first);

コンストラクターの 1 つBigAが呼び出されます。Aオブジェクトへの参照を取るため、firstコピーされません (参照は値を提供するときに設定されます)。

次に、メンバー初期化子リストの時間が来て、

BigA(A& a) :
            data1(a), data2(a)

data1あり、タイプがである場合Afirstオブジェクトはコピーされます (ここでは として参照されますa) 。

新しいAオブジェクトは、独自のコピー コンストラクターによって作成されます。最初に、 のコピー コンストラクターを呼び出しますA1

A(const A& a) :
a1(a.a1)

I am copy constructing an A1

次に、とAフィールドがデフォルトで初期化されます。a2a3

I am constructing an A2 with: 20
I am constructing an A3 

次に、コピー コンストラクターの本体A1が実行されます。

I am copy constructing an A

初期化に戻りましょうBigA。これまで初期化について話してきましたがdata1、今度はA& data2:

BigA(A& a) :
            data1(a), data2(a)

これは参照であり、初期化するために参照が渡されるため、単なる割り当てであり、出力はありません。

BigAコンストラクター ( を取るA&) body が実行されます:

I just constructed a BigA

さて、何が起こっているのかを明確にしようと思います

volta(biga).get(2).change();

この関数が呼び出されています:

BigA volta(BigA& biga)
{
    cout << "Volta ta data?" << endl;
    return biga;
}

繰り返しになりますが、参照による受け渡しでは、コピー コンストラクターの呼び出しは発生しません。

関数本体が実行されています。

"Volta ta data?"

この関数は class の名前のないオブジェクトを返すBigAため、コピー コンストラクターを呼び出す必要があります。

のようなコピー コンストラクタが提供されていないBigA (const BigA & biga)ため、デフォルトのコピー コンストラクタが呼び出されています。順次メンバーの初期化をA data1;行い、次にA& data2;

最初のメンバーはdata1、名前のないオブジェクトのフィールドをコピーすることによって初期化されるため、のコピー コンストラクターAが呼び出されます。ここに出力される内容は上記で説明されています (参照: A new Aobject is created by its own copy constructor... )

I am copy constructing an A1
I am constructing an A2 with: 20
I am constructing an A3
I am copy constructing an A

次に、getメソッドは次のように実行されますindex == 2

A get(int index) {
        if (index == 1)
            return data1;
        else
            return data2; // <--- this line is executed

data2isA&であり、メソッドが returnAを返すと、Aコピー コンストラクターが実行されます。

I am copy constructing an A1
I am constructing an A2 with: 20
I am constructing an A3
I am copy constructing an A

最後に、change実行します

void change() {
        a1.change();
        a2.change();
        a3.change();
    }

そして何かだけa3.change()を印刷します:

Nothing to change

プログラム終了時

破棄は逆の順序で行われ、最後に作成されたchangeオブジェクトが最初に破棄されます。

I am destroying an A
I am destroying an A3
I am destroying an A2 with: 400
I am destroying an A1 with: 100

I am destroying a BigAは 2 回印刷されますが、I just constructed a BigA1 回だけです。後者は、BigAそのテイクのコピー コンストラクターがないためですconst & BigA(上記でも指摘されています)。

お問い合わせへの回答

void change() {
    A& rdata1 = data1;
    A cdata2 = data2;
}
//in the main():
biga.change();

A cdata2 = data2;はい、オブジェクトcdata2が以前に初期化されていないため、ここでコピー コンストラクターが呼び出されることは間違いありません。これは、この参照の下でよく説明されているケースです。

このようにコードを変更すると

A cdata2;
cdata2 = data2;

予想される割り当てが表示されます。

I am constructing an A1 with: 10
I am constructing an A2 with: 20
I am constructing an A3
I am constructing an A
I am performing a stupid assignment between As
于 2016-02-08T11:50:04.673 に答える