/*
* http://sosal.tistory.com/
* made by so_Sal
*/
복사생성자에 관한 문제를 보고 정리해볼겸 트랙백 날립니다 ^-^
C++에는 2가지 종류의 변수 초기화 방법을 제공합니다.
int main(){
int a = 10; <-- C 스타일 초기화
int b(10); <-- C++스타일 초기화
cout<<a<<endl<<b<<endl;
return 0;
}
a와 b 모두 10이란 값을 출력합니다.
그럼 변수를 이렇게 두 가지 형태로 초기화가 가능하다면,
객체도 두 가지 형태로 가능하지 않을까? 란 생각을 할 수 있는데요,
#include<iostream>
using namespace std;
class data{
private:
int value;
public:
data(int a){
value=a; //간단한 생성자
}
void output(){
cout<<value<<endl;
}
};
int main(){
data a(10);
data b=10;
a.output();
b.output();
return 0;
}
실행 결과 모두 10을 출력합니다.
이 실행결과를 통해서, C, C++ 초기화 스타일 모두 가능하다는 것을 알 수 있습니다.
하지만, 객체 생성에서의 C 스타일은 (data b=10;) 묵시적으로 컴파일 과정에서
data b(10); 으로 변환이 이뤄지는 것이기 때문에, 동일하다고 볼 수는 없습니다.
디폴드 복사생성자와, 얕은 복사
#include<iostream>
#include<cstring>
using namespace std;
class data{
private:
char value[100];
public:
data(char *val){ //생성자는 char* 자료형만 받는다.
strcpy(value,val); //하지만 메인에서 data b를 선언하는곳을 보면
}
void output(){
cout<<value<<endl;
}
};
int main(){
data a("somebody help me");
data b(a); //char* 자료형을 넣은것이 아니라, data 객체를 넣었다.
a.output();
b.output();
return 0;
}
data 객체는 char* 자료형과 분명히 다른것인데, 어떻게 이게 가능할까?
data b(a)에서 객체 생성이 성공했다는 것은, data 자료형을 받는 생성자 함수가
자동으로 삽입되었다고 생각할 수 밖에 없다. 하지만 분명히 그런 생성자 함수를 만들지 않았다.
우리는 이런 자기 자신과 같은 형태의 객체를 인자로 받을 수 있는 생성자가
자동으로 만들어진것을 디폴트 복사 생성자라 한다.
(자기 자신과 같은 형태의 객체를 받는것을 복사 생성자라고 한다.)
즉 디폴트 복사 생성자의 기능은, 멤버 대 멤버를 복사하는 것인데,
클레스마다 가지고 있는 데이터들이 다를것이기 때문에,
디폴트 생성자는 각 클레스마다 다른 형태일 것이다. 라고 예측할 수 있다.
하지만, 편리한 디폴트 생성자에게는 아주 큰 문제점이 존재한다.
#include<iostream>
#include<cstring>
using namespace std;
class data{
private:
char *name; //객체의 멤버변수를 참조하는 형식으로 만들어보자
char *phone;
int age;
public:
data(char *_name, char* _phone, int _age){
name = new char[strlen(_name)+1];
strcpy(name,_name);
phone = new char[strlen(_phone)+1];
strcpy(phone,_phone);
age = _age;
}
void output(){
cout<<name<<endl;
cout<<phone<<endl;
cout<<age<<endl;
}
void modify(char *val){
strcpy(name,val);
}
~data(){
delete []name;
delete []phone;
} //소멸자에서 멤버변수 다 없애줘야겠죠?
};
int main(){
data *a = new data("sosal","010-6450-7939",21);
data b(*a);
a->output();
a->modify("aaa");
b.output();
delete a;
b.output();
return 0;
}
위 문제의 소스를 제대로 분석해보면
엄청나게 큰 문제점을 찾을 수 있다.
말그대로, 디폴트 복사 생성자는
직접 값을 복사하는것이 아니라
"참조" 하고 있던것이다.
이를 얕은 복사라 하며,
객체가 실제로 데이터를 가지고 있는것이
아님을 알 수 있다.
와.. 이해 진짜 잘된다. 박수한번 치자. 짞짞짜까ㅉ까짜까ㅉ까짞짜까짜까
그럼, 디폴트 복사생성자가 수행하는 얕은복사 말고, 깊은 복사를 해보자.
깊은 복사를 하기 위해선, 우리가 직접 복사생성자를 정의할것이다.
#include<iostream>
#include<cstring>
using namespace std;
class data{
private:
char *name;
char *phone;
int age;
public:
data(char *_name, char* _phone, int _age){
name = new char[strlen(_name)+1];
strcpy(name,_name);
phone = new char[strlen(_phone)+1];
strcpy(phone,_phone);
age = _age;
}
data(const data& object){
name = new char[strlen(object.name)+1];
strcpy(name,object.name);
// 이경우, private 멤버변수도 접근이 가능하므로, 되도록 매개변수를 const로 설정
phone = new char[strlen(object.phone)+1];
strcpy(phone,object.phone);
age = object.age;
}
void output(){
cout<<name<<endl;
cout<<phone<<endl;
cout<<age<<endl;
}
void modify(char *val){
strcpy(name,val);
}
~data(){
delete []name;
delete []phone;
}
};
int main(){
data *a = new data("sosal","010-6450-7939",21);
data b(*a);
a->output();
delete a;
b.output();
}
* 참고자료 : 열혈강의 C++ 윤성우 저
'Programing > C- programing' 카테고리의 다른 글
C++ : Const 함수 속성 (0) | 2010.09.14 |
---|---|
C++ - inline function 인라인 함수 (0) | 2010.09.14 |
Topological sort 알고리즘 (0) | 2010.09.01 |
Default Parameter를 이용한 피보나치 수열 (0) | 2010.09.01 |
Hash function - 나눗셈법 (0) | 2010.09.01 |