20

引数なしのコンストラクターで初期化リストからメンバーを除外すると、そのメンバーの既定のコンストラクターが呼び出されることはわかっています。

コピー コンストラクターも同様にメンバーのコピー コンストラクターを呼び出しますか、それとも既定のコンストラクターも呼び出しますか?

class myClass {
  private:
    someClass a;
    someOtherClass b;
  public:
    myClass() : a(DEFAULT_A) {} //implied is b()
    myClass(const myClass& mc) : a(mc.a) {} //implied is b(mc.b)??? or is it b()?
}
4

8 に答える 8

31

明示的に定義されたコピー コンストラクターは、メンバーのコピー コンストラクターを呼び出しません。

コンストラクターの本体に入ると、そのクラスのすべてのメンバーが初期化されます。つまり、一度到達する{と、すべてのメンバーが初期化されていることが保証されます。

指定しない限り、メンバーはクラスに表示される順序でデフォルトで初期化されます。(そして、そうできない場合、プログラムの形式が正しくありません。) したがって、独自のコピー コンストラクターを定義する場合、任意のメンバー コピー コンストラクターを必要に応じて呼び出すのはあなた次第です。

これは、どこかにコピーして貼り付けていじることができる小さなプログラムです。

#include <iostream>

class Foo {
public:
    Foo() {
        std::cout << "In Foo::Foo()" << std::endl;
    }

    Foo(const Foo& rhs) {
        std::cout << "In Foo::Foo(const Foo&)" << std::endl;
    }
};

class Bar {
public:
    Bar() {
        std::cout << "In Bar::Bar()" << std::endl;
    }

    Bar(const Bar& rhs) {
        std::cout << "In Bar::Bar(const Bar&)" << std::endl;
    }
};

class Baz {
public:
    Foo foo;
    Bar bar;

    Baz() {
        std::cout << "In Baz::Baz()" << std::endl;
    }

    Baz(const Baz& rhs) {
        std::cout << "In Baz::Baz(const Baz&)" << std::endl;
    }
};

int main() {
    Baz baz1;
    std::cout << "Copying..." << std::endl;
    Baz baz2(baz1);
}

現状では、これは以下を出力します:

Foo::Foo() で
In Bar::Bar()
Baz::Baz() で
コピー中...
Foo::Foo() で
In Bar::Bar()
In Baz::Baz(const Baz&)

のメンバーをデフォルトで初期化していることに注意してくださいBaz

次のように、明示的なコピー コンストラクターをコメント アウトします。

/*
Baz(const Baz& rhs) {
    std::cout << "In Baz::Baz(const Baz&)" << std::endl;
}
*/

出力は次のようになります。

Foo::Foo() で
In Bar::Bar()
Baz::Baz() で
コピー中...
Foo::Foo(const Foo&) で
In Bar::Bar(const Bar&)

両方でコピー コンストラクターを呼び出します。

そして、Bazのコピー コンストラクターを再導入し、単一のメンバーを明示的にコピーすると、次のようになります。

Baz(const Baz& rhs) :
    foo(rhs.foo)
{
    std::cout << "In Baz::Baz(const Baz&)" << std::endl;
}

我々が得る:

Foo::Foo() で
In Bar::Bar()
Baz::Baz() で
コピー中...
Foo::Foo(const Foo&) で
In Bar::Bar()
In Baz::Baz(const Baz&)

ご覧のとおり、コピー コンストラクターを明示的に宣言すると、すべてのクラス メンバーのコピーを担当しますそれは今あなたのコンストラクタです。

これは、移動コンストラクターを含むすべてのコンストラクターに適用されます。

于 2009-04-16T04:26:29.347 に答える
2

初期化リストにそのメンバー変数の他のコンストラクター呼び出しを明示的に追加していない場合、既定のコンストラクターを持つメンバー変数の場合、その既定のコンストラクターが呼び出されます。

于 2009-04-16T04:27:05.150 に答える
1

はい。セクターはセクターです。

于 2009-04-16T04:08:33.963 に答える
1

必要に応じてコンパイラが追加することを除けば、コピー コンストラクターには魔法のようなものは何もありません。しかし、実際の実行方法には特別なことはありません。「そのようなコンストラクタを使用する」と明示的に言わなければ、デフォルトが使用されます。

于 2009-04-16T04:30:06.220 に答える
1

基本呼び出しコンストラクターの開始方法に応じて、メンバーのコンストラクターは同じ方法で呼び出されます。たとえば、次から始めましょう。

struct ABC{
    int a;
    ABC() : a(0)    {   printf("Default Constructor Called %d\n", a);   };

    ABC(ABC  & other )  
    {
        a=other.a;
        printf("Copy constructor Called %d \n" , a ) ;
    };
};

struct ABCDaddy{
    ABC abcchild;
};

次のテストを実行できます。

printf("\n\nTest two, where ABC is a member of another structure\n" );
ABCDaddy aD;
aD.abcchild.a=2;

printf( "\n Test: ABCDaddy bD=aD;  \n" );
ABCDaddy bD=aD; // Does call the copy constructor of the members of the structure ABCDaddy ( ie. the copy constructor of ABC is  called)

printf( "\n Test: ABCDaddy cD(aD); \n" );
ABCDaddy cD(aD);    // Does call the copy constructor of the members of the structure ABCDaddy ( ie. the copy constructor of ABC is  called)

printf( "\n Test: ABCDaddy eD; eD=aD;  \n" );
ABCDaddy eD;
eD=aD;          // Does NOT call the copy constructor of the members of the structure ABCDaddy ( ie. the copy constructor of ABC is not called)

出力:

Default Constructor Called 0

Test: ABCDaddy bD=aD;
Copy constructor Called 2

Test: ABCDaddy cD(aD);
Copy constructor Called 2

Test: ABCDaddy eD; eD=aD;
Default Constructor Called 0

楽しみ。

于 2011-08-31T17:45:34.100 に答える
1

VC9 にはありません。他の人についてはわかりません。

// compiled as: cl /EHsc contest.cpp
//
//    Output was:
//    Child1()
//    -----
//    Child1()
//    Child2()
//    Parent()
//    -----
//    Child1(Child1&)
//    Child2()
//    Parent(Parent&)

#include <cstdio>

class Child1 {
    int x;
public:
    static Child1 DEFAULT;

    Child1(){
        x = 0;
        printf("Child1()\n");
    }

    Child1(Child1 &other){
        x = other.x;
        printf("Child1(Child1&)\n");
    }
};

Child1 Child1::DEFAULT;

class Child2 {
    int x;
public:
    Child2(){
        x = 0;
        printf("Child2()\n");
    }

    Child2(Child2 &other){
        x = other.x;
        printf("Child2(Child2&)\n");
    }
};

class Parent {
    int x;
    Child1 c1;
    Child2 c2;

public:
    Parent(){
        printf("Parent()\n");
    }

    Parent(Parent &other) : c1(Child1::DEFAULT) {
        printf("Parent(Parent&)\n");
    }
};

int main(){
    printf("-----\n");
    Parent p1;
    printf("-----\n");
    Parent p2(p1);

    return 0;
}
于 2009-04-16T05:25:55.603 に答える
0

コンパイラがデフォルトのcctorを提供するとき、コンパイラはメンバー変数に対して何をすると思いますか? それをコピーして構築します。

同様に、cctor がユーザー定義の場合、一部のメンバーを除外すると、それらのメンバーを初期化せずに残すことはできません。クラスの不変条件は構築中に確立され、常に維持する必要があります。したがって、コンパイラがそれを行います。

于 2009-04-16T04:28:44.990 に答える