C ++ 다른 객체를 포함하는 클래스의 암시 적 복사 생성자
-
05-07-2019 - |
문제
직접 구현하지 않으면 컴파일러가 때때로 기본 사본 생성자를 제공한다는 것을 알고 있습니다. 이 생성자가 정확히 무엇을하는지 혼란스러워합니다. 다른 객체가 포함 된 클래스가있는 경우, 그 중 신고 된 사본 생성자가없는 경우 동작은 무엇입니까? 예를 들어, 다음과 같은 클래스 :
class Foo {
Bar bar;
};
class Bar {
int i;
Baz baz;
};
class Baz {
int j;
};
이제 내가 이것을한다면 :
Foo f1;
Foo f2(f1);
기본 카피 생성자는 무엇을합니까? 컴파일러 생성 카피 생성자가 Foo
컴파일러 생성 생성자를 호출하십시오 Bar
복사합니다 bar
, 그런 다음 컴파일러 생성 사본 생성자를 호출합니다. Baz
?
해결책
Foo f1;
Foo f2(f1);
예, 이것은 당신이 기대하는 것을 할 것입니다.
f2 사본 생성자 foo :: foo (foo const &)가 호출됩니다.
이 사본은 기본 클래스를 구성한 다음 각 멤버 (재귀 적으로)를 구성합니다.
다음과 같은 클래스를 정의하는 경우 :
class X: public Y
{
private:
int m_a;
char* m_b;
Z m_c;
};
다음 방법은 컴파일러에 의해 정의됩니다.
- 생성자 (기본값) (2 버전)
- 생성자 (사본)
- 소멸자 (기본값)
- 과제 연산자
생성자 : 기본값 :
실제로 두 개의 기본 생성자가 있습니다.
하나는 사용됩니다 zero-initialization
다른 하나는 사용됩니다 value-initialization
. 중고는 사용 여부에 따라 다릅니다 ()
초기화 중지 여부.
// Zero-Initialization compiler generated constructor
X::X()
:Y() // Calls the base constructor
// If this is compiler generated use
// the `Zero-Initialization version'
,m_a(0) // Default construction of basic PODS zeros them
,m_b(0) //
m_c() // Calls the default constructor of Z
// If this is compiler generated use
// the `Zero-Initialization version'
{
}
// Value-Initialization compiler generated constructor
X::X()
:Y() // Calls the base constructor
// If this is compiler generated use
// the `Value-Initialization version'
//,m_a() // Default construction of basic PODS does nothing
//,m_b() // The values are un-initialized.
m_c() // Calls the default constructor of Z
// If this is compiler generated use
// the `Value-Initialization version'
{
}
참고 : 기본 클래스 또는 멤버에 유효한 표시 기본 생성자가없는 경우 기본 생성자를 생성 할 수 없습니다. 코드가 기본 생성자를 사용하려고 시도하지 않는 한 오류가 아닙니다 (그런 다음 컴파일 시간 오류 만).
생성자 (사본)
X::X(X const& copy)
:Y(copy) // Calls the base copy constructor
,m_a(copy.m_a) // Calls each members copy constructor
,m_b(copy.m_b)
,m_c(copy.m_c)
{}
참고 : 기본 클래스 또는 멤버에 유효한 가시 카피 생성자가없는 경우 카피 생성자를 생성 할 수 없습니다. 코드가 사본 생성자를 사용하려고 시도하지 않는 한 오류가 아닙니다 (그런 다음 컴파일 시간 오류 만).
과제 연산자
X& operator=(X const& copy)
{
Y::operator=(copy); // Calls the base assignment operator
m_a = copy.m_a; // Calls each members assignment operator
m_b = copy.m_b;
m_c = copy.m_c;
return *this;
}
참고 : 기본 클래스 또는 멤버에 유효한 실행 가능한 할당 연산자가없는 경우 할당 연산자를 생성 할 수 없습니다. 코드가 할당 연산자를 사용하려고 시도하지 않는 한 오류가 아닙니다 (그런 다음 컴파일 시간 오류 만).
폐물 소각로
X::~X()
{
// First runs the destructor code
}
// This is psudo code.
// But the equiv of this code happens in every destructor
m_c.~Z(); // Calls the destructor for each member
// m_b // PODs and pointers destructors do nothing
// m_a
~Y(); // Call the base class destructor
- 만약에 어느 생성자 (사본 포함)가 선언 된 다음 기본 생성자는 컴파일러에 의해 구현되지 않습니다.
- 카피 생성자가 선언되면 컴파일러가 하나를 생성하지 않습니다.
- 할당 연산자가 선언되면 컴파일러가 하나를 생성하지 않습니다.
- 소멸자가 선언되면 컴파일러는 컴파일러가 하나를 생성하지 않습니다.
코드를보고 다음 사본 생성자가 생성됩니다.
Foo::Foo(Foo const& copy)
:bar(copy.bar)
{}
Bar::Bar(Bar const& copy)
:i(copy.i)
,baz(copy.baz)
{}
Baz::Baz(Baz const& copy)
:j(copy.j)
{}
다른 팁
컴파일러는 귀하가 아닌 한 사본 생성자를 제공합니다 선언하다 (참고 : 아닙니다 정의하다) 하나 자신. 컴파일러 생성 카피 생성자는 단순히 클래스의 각 구성원 (및 각 기본 클래스)의 사본 생성자를 호출합니다.
과제 연산자와 파괴자 BTW에 대해서도 마찬가지입니다. 그러나 기본 생성자와는 다릅니다. 다른 생성자를 직접 선언하지 않는 경우에만 컴파일러가 제공합니다.
예, 컴파일러 생성 카피 생성자는 멤버가 포함 된 클래스에서 선언 된 순서대로 멤버 별 사본을 수행합니다. 멤버 유형 중 하나가 카피 생성자를 제공하지 않으면 포함 된 클래스의 사본 생성자를 생성 할 수 없습니다. 아마도 다른 생성자 중 하나를 사용하여 카피로 구성 할 수없는 멤버의 값을 초기화하기 위해 적절한 수단을 결정할 수 있다면 수동으로 하나를 작성할 수 있습니다.
컴파일러는 필요한 생성자를 생성합니다.
그러나 카피 건설자를 직접 정의하자마자 컴파일러는 해당 클래스에 대해 무엇이든 생성을 포기하고 적절한 생성자가 정의되어 있지 않으면주고 오류가 발생합니다.
예제 사용 :
class Baz {
Baz(const Baz& b) {}
int j;
};
class Bar {
int i;
Baz baz;
};
class Foo {
Bar bar;
};
BAZ가 카피 구성 가능하지 않고 컴파일러가 FOO의 기본값 및 복사 Corpetoctor를 생성 할 수 없기 때문에 기본 인스턴스화 또는 카피 구성 FOO를 시도하면 오류가 발생합니다.