2009-04-16 21 views
14

引数なしコンストラクタの初期化リストからメンバを離れると、そのメンバのデフォルトのコンストラクタが呼び出されることがわかっています。コンストラクタの初期化リストをコピーする

同様に、コピーコンストラクタはメンバーのコピーコンストラクタをコールするのですか、またはデフォルトのコンストラクタも呼び出しますか?

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()? 
} 
+2

参照:http://stackoverflow.com/questions/563221/is-there-an-implicit-default-constructor-in-c/563320#563320 –

答えて

23

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

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

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

#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); 
} 

として、次のとおりです:

 
In Foo::Foo() 
In Bar::Bar() 
In Baz::Baz() 
Copying... 
In Foo::Foo() 
In Bar::Bar() 
In Baz::Baz(const Baz&) 

注意を、それがデフォルト初期化のメンバーをだとここで

は、コピー&ペーストすることができますどこかと周りの混乱に小さなプログラムですBaz

のように、明示的なコピーコンストラクタをコメントアウトすることにより:

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

出力は、このになります:

 
In Foo::Foo() 
In Bar::Bar() 
In Baz::Baz() 
Copying... 
In 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; 
} 

我々が得る:

 
In Foo::Foo() 
In Bar::Bar() 
In Baz::Baz() 
Copying... 
In Foo::Foo(const Foo&) 
In Bar::Bar() 
In Baz::Baz(const Baz&) 

をあなたが見ることができるように、明示的にコピーコンストラクタを宣言したら、 はすべてのクラスメンバーのコピーを担当します。それは今あなたのコンストラクタです。

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

+0

メンバーが生のポインタ(例えばvoid *)またはint、doubleなどの場合はどう? - ユーザー定義コピーコンストラクタは0に{コピーコンストラクタの初期化リストでユーザーがこれらのメンバーに何も割り当てていない場合 –

+0

@SergeRogatch:明示的に初期化しないと、値は未初期化の通常の変数のように指定されず、未定義の動作です。明示的にnull、ints、0などへのポインタを初期化する必要があります。 – GManNickG

2

はい。 Ctorはctorsです。

+0

+1、あなたは2秒遅れます。 :) –

+1

-1:「はい」は、「または」を含む質問への回答として何を意味しますか? – mmmmmmmm

+1

rstevens、質問はチャーリーが答えた直後に編集されました。チャーリーは元の質問に完全に答えました。それは私が以下の私の答えを編集したと私はそれが十分だと思うと思った:) – GManNickG

2

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

0

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

同じように、cctorがユーザー定義で、一部のメンバーを除外した場合、そのメンバーを初期化しないままにすることはできません。階級不変量は建設中に確立され、常に維持されなければならない。だから、コンパイラはあなたのためにそれを行います。

+0

-1残念です。コンパイラが提供するデフォルトのコピーctor *は、そのメンバのコピーctor(プリミティブ型の場合はビット単位のコピー)を使用して各メンバをコピーします。 –

+0

はい、私は同じことを言っています! * Default Initilalizes *はメンバcctorを介したコピーを意味します。 – Abhay

+0

私はあなたが言っていることを見ていますが、実際には "default initialises"という用語は、C++標準で明確に定義された意味を持ちます。これは、型のデフォルト値でオブジェクトを初期化することですとにかく...)あなたの説明は少し誤解を招く。 –

1

コピーコンストラクタに関して魔法はありません。コンパイラが必要に応じて追加します。しかし、実際にどのように動作するかは特別なものはありません。「そうしたコンストラクタを使用する」と明示的に言わないと、デフォルトを使用します。

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; 
} 
+0

そして、stdoutは? –

2

参照:Is there an implicit default constructor in C++?

ショート:

  • コンパイラ "デフォルトコンストラクタを" 生成:各メンバーのデフォルトコンストラクタを使用しています。
  • コンパイラによって生成された "コピーコンストラクタ":各メンバのコピーコンストラクタを使用します。
  • コンパイラによって生成された「代入演算子」:各メンバの代入演算子を使用します。
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 

をお楽しみください。

関連する問題