C++ 스타일의 초기화
C++은 두가지 형태의 선언 및 초기화를 제공한다
int num =20;
int num(20);
int &ref=num;
int &ref(num);
이와같이 , 클래스를 선언및 초기화할때 멤버대 멤버 복사가 진행된다.
복사생성자
SoSimple sim1 (15,20);
SoSimple sim2 = sim1; // 멤버끼리의 얕은복사 , SoSimple sim2 =sim1 은 SoSimple sim2(sim1)으로 변환된다. ( 묵시적 변환 )
SoSimple sim2(sim1) 에 담겨있는 의미는 다음과 같다.
SoSimple 형 객체를 생성하라.
객체의 이름은 sim2로 한다.
sim1을 인자로 받을수 있는 생성자의 호출을 통해서 객체생성을 완료한다. ( 복사생성자 )
복수생성자를 따로 정의하지않으면 디폴트 복수생성자라는것이 자동으로 생성된다.
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) {} // 복사생성자, 정의하지않을시 디폴트 복사생성자 자동삽입
// 복사 생성자의 매개변수는 항상 참조형이여야한다 ( & ) . 참조형으로 선언하지않으면 복사생성자의 호출이 무한루프에 빠지기때문이다. 참조형으로 선언하지않으면 객체의 인자 전달시에도 복사생성자의 호출이 필요하기 때문이다.
};
묵시적 변환이 일어나지않게 하고싶을때 : explicit 키워드
explicit SoSimple ( const SoSimple ©) : num(copy,num1) , num2(copy.num2) {} 와 같은방식으로 복사생성자를 정의하면 묵시적 변환을 제한할 수 있다. 묵시적변환이 많이 발생하는 코드일수록 코드의 결과를 예측하기가 어려워지기때문에, explicit 키워드는 코드의 명확함을 더하기위해 자주 사용된다.
얕은복사와 깊은복사
디폴트 복사생성자는 멤버대 멤버의 복사를 진행하는데 , 이는 얕은복사이기때문에 멤버변수가 힙의 메모리 공간을 참조하는 경우에, 복사시 멤버변수가 같은 주소값을 참조하여 완벽하게 분리된 객체가 아니게되어 문제가 될 수 있다.
class Person
{
private :
char * name;
int age;
public :
Person(char * myname , int myage )
{
int len = strlen(myname)+1;
name = new char[len];
strcpy(name,myname);
age = myage;
}
~Person()
{
delete []name;
}
};
클래스가 이렇게 정의되어있을때 , 디폴트 복사생성자로 복사를 하게되면 (얕은복사) 복사한 객체와 원래 객체의 name 멤버가 가리키는 주소값이 동일하게되어 한 객체가 소멸될때 , name 값 또한 소멸하게되어 나머지 객체의 소멸자 호출시 delete []name; 에서 컴파일오류가 생성된다. 따라서 이럴땐 복사생성자를 깊은복사를 할 수 있게 정의해두어야한다.
Person(const Person ©) : age(copy.age)
{
name = new char [strlen(copy.name)+1];
strcpy(name,copy.name);
}
복사 생성자의 호출시점
case1 : 기존에 생성된 객체를 이용해서 새로운 객체를 초기화하는 경우
case2 : Call - by - Value 방식의 함수호출 과정에서 객체를 인자로 전달하는 경우
case3 : 객체를 반환하되 , 참조형으로 반환하지 않는 경우
공통점 : 객체를 새로 생성해야하고 , 생성과 동시에 동일한 자료형의 객체로 초기화해야한다 !
메모리 공간의 할당과 초기화가 동시에 일어나는 상황
int num1=num2; // case1
SimpleFunc(num); // case2 , 호출
return n; // case3 - 함수가 값을 반환하면 별도의 메모리공간이 할당되고 이 공간에 반환값이 저장된다.
void SimpleFuncObj1 ( SoSimple ob )
{
ob.ShowData();
}
SoSimple SimpleFuncObj2 ( SoSimple ob )
{
return ob;
}
SoSimple sim2 =sim1;
SimpleFuncObj1(sim1); // case2 , 매개변수 ob에 sim1 전달시 복사생성자 호출
SimpleFuncObj2(sim1); // case2 , case3 둘다일어남 , return 으로 객체 반환시 임시객체라는것이 생성되고 임시객체의 참조값을 반환한다.
임시객체는 참조자에 참조되지않는이상 다음 행으로 넘어가면 바로 소멸된다. ( 참조자로 참조하지않으면 다음행에서 접근할 수 없기때문 )
'C++언어 > 열혈C++' 카테고리의 다른 글
C++ : Chapter -7 상속의 이해 (0) | 2018.05.20 |
---|---|
C++ : Chpater -6 friend , static 그리고 const (1) | 2018.05.16 |
C++ : Chapter -4 클래스 PART2 (0) | 2018.05.02 |
C++ : Chapter -3 클래스 PART1 (0) | 2018.04.26 |
C++ : Chapter -2 참조자와 new&delete (0) | 2018.04.20 |