2009-04-16 7 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 : 명시 적으로 초기화하지 않으면 값은 일반 초기화되지 않은 변수와 같이 지정되지 않으며 읽지 않은 동작은 정의되지 않은 동작입니다. 명시 적으로 널, 0 등의 포인터를 초기화해야합니다. – GManNickG

2

예. Ctors는 ctors입니다.

+0

+1, 2 초 전입니다. :) –

+1

-1 : "예"는 "또는"을 포함하는 질문에 대한 답변으로 의미합니까? – mmmmmmmm

+1

rstevens, 질문은 찰리가 대답 한 직후에 수정되었습니다. 찰리는 원래의 질문에 완벽하게 대답했습니다. 즉, 아래에서 내 대답을 편집하고 충분하다고 생각합니다. – GManNickG

2

초기화 생성자에 다른 멤버 생성자 호출을 명시 적으로 추가하지 않은 경우 기본 생성자가 호출되는 기본 생성자가있는 멤버 변수의 경우.

0

컴파일러가 기본 cctor를 제공하면 컴파일러가 멤버 변수에 대해 어떻게 생각합니까? 그것 복사본 구조 그것.

같은 맥락에서 cctor가 사용자 정의이고 일부 구성원을 제외하면 이러한 구성원을 초기화하지 않은 상태로 둘 수 없습니다. 계급 불변량은 건설 중에 설정되며 지속적으로 유지되어야합니다. 그래서, 컴파일러는 당신을 위해 그렇게합니다.

+0

-1 미안. 컴파일러가 제공하는 기본 복사본 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 

을 즐길 수 있습니다.