[C++] 5-1. 복사 생성자
int obj1 = obj2;
---------------------------
int obj1;
obj1 = obj2;
복사 생성자가 필요한 이유 :
대입 연산 즉, 새로운 객체를 기존의 객체로 초기화하는 대입 연산의 결과를 정의하게끔 하도록 하기 위해서 만들어짐
C++ 스타일의 초기화
//C 스타일 초기화
int num = 20;
int &ref = num;
//C++ 스타일 초기화
int num(20);
int &ref(num);
복사 생성자를 정의하지 않으면, 멤버 대 멤버의 복사를 진행하는 디폴트 복사 생성자가 삽입된다.
class SoSimple
{
private:
int num1;
int num2;
public :
SoSimple(int n1, int n2) : num1(n1), num2(n2)
{ }
//==================삽입된 디폴트 복사 생성자====================
SoSimple(const SoSimple ©) : num1(copy.num1), num2(copy.num2)
{ }
//===============================================================
void ShowSimpleData()
{
cout<<num1<<endl;
cout<<num2<<endl;
}
};
int main(void){
SoSimple sim1(15,20);
SoSimple sim2 = sim1;
//SoSimple (sim1,sim2)의 생성자 필요
//해당 유형의 생성자가 정의되어 있지 않으면 자동으로 생성자가 삽입된다.
//=> 복사 생성자
//다른 생성자의 정의와 상관 없이,복사 생성자가 정의되어있지 않으면
//디폴트 복사 생성자가 자동으로 삽입된다.
sim2.ShowSimpleData();
return 0;
}
다음 문장에서 sim2객체를 새로 생성해서, 객체 sim1과 sim2간의 멤버 대 멤버 복사가 일어난다.
SoSimple sim2 = sim1;
아래 문장들은 서로 동일한 의미로 해석된다.
int num1 = 2;
int num1(num2);
SoSimple sim2 = sim1;
SoSimple sim2(sim1);//대입 연산에서 일어나야 할 일들을 생성자를 통해 정의
SoSimple sim2(sim1);
SoSimple sim2(sim1);
위의 객체 생성문에서 호출하고자 하는 생성자는 다음과 같이 SoSimple객체를 인자로 받을 수 있는 생성자이다.
SoSimple(SoSimple ©){
...
}
SoSimple sim2=sim1; 이 문장도 다음의 형태로 자동 변환되어서 객체가 생성되는 것이다.
SoSimple sim2(sim1);
SoSimple(const SoSimple &ref){ } //생성자
예제
#include <iostream>
using namespace std;
class SoSimple
{
private:
int num1;
int num2;
public:
SoSimple(int n1, int n2)
: num1(n1), num2(n2)
{
//empty
}
//==================삽입된 디폴트 복사 생성자====================
SoSimple(const SoSimple& copy)//const : 대입 이후에 대입한 변수의 값이 변경되는 상황을 방지
: num1(copy.num1), num2(copy.num2)
{
cout << "Called SoSimple(SoSimple ©)" << endl;
}
//===============================================================
void ShowSimpleData()
{
cout << num1 << endl;
cout << num2 << endl;
}
};
int main(void) {
SoSimple sim1(15, 30);
cout << "생성 및 초기화 직전" << endl;
SoSimple sim2 = sim1;//SoSimple sim2(sim1);로 변환
//SoSimple (sim1,sim2)의 생성자 필요
//해당 유형의 생성자가 정의되어 있지 않으면 자동으로 생성자가 삽입된다.
//=> 복사 생성자
//다른 생성자의 정의와 상관 없이,복사 생성자가 정의되어있지 않으면
//디폴트 복사 생성자가 자동으로 삽입된다.
cout << "생성 및 초기화 직후" << endl;
sim2.ShowSimpleData();
return 0;
}
위 코드의 생성자를 '복사 생성자(copy constructor)'라고 부른다.
복사 생성자는 다른 일반 생성자와 호출되는 시점이 다르다.
키워드 explicit
SoSimple sim2 = sim1; => SoSimple sim2(sim1);
C++에서의 이러한 묵시적 형 변환은 복사 생성자를 explicit으로 선언하면 막을 수 있다.
explicit SoSimple(const SoSimple ©)
: num1(copy.num1), num2(copy.num2)
{
//empty!!
}
explicit은 묵시적 변환을 막아서 코드의 명확함을 더해준다.
복사 생성자뿐만 아니라, 전달 인자가 하나인 생성자에서도 묵시적 변환이 일어난다.
class AAA
{
private :
int num;
public :
explicit AAA(int n) : num(n) { }
....
};
AAA생성자를 explicit로 설정하면 AAA obj = 3과 같은 형태로 객체 생성이 불가능하다.
AAA obj(3);의 형태로 객체를 생성해야만 한다.