005. 복사 생성자
I. C,C++ 스타일 초기화
-
C 에서의 스타일 초기화
- int val = 10;
-
C++에서의 스타일 초기화
- int val(10); or int val = 10;
II. 복사 생성자의 형태
- #include <iostream>
using namespace std; - class AAA
{
public:
AAA()
{
cout<<"AAA() 호출"<<endl;
}
AAA(int i)
{
cout<<"AAA(int i) 호출"<<endl;
}
AAA(const AAA& a)
{
cout<<"AAA(const AAA& a) 호출"<<endl;
}
}; - int main()
{
AAA obj1;
AAA obj2(10);
AAA obj3(obj2);
return 0;
}
- 위의 소스에 main안에 보면 AAA obj3(obj2); 이것이 복사 생성자이다. 복사 생성자를 선언 할 경우 &는 꼭 선언을 해줘야 한다.
III. 디폴트 복사 생성자
-
디폴트 복사 생성자 형태
- Point(const Point &p) 이런 식을 들어간다.
- #include <iostream>
- using namespace std;
- class Point
{
int x,y;
public:
Point(int _x,int _y)
{
x = _x;
y = _y;
}
/*
Point(const Point &p)
{
x = p.x;
y = p.y;
}*/ //디폴트 복사 생성자
void ShowData()
{
cout<<x<<' '<<y<<endl;
}
}; - int main()
{
Point p1(10,20);
Point p2(p1); - p1.ShowData();
p2.ShowData();
}
- 디폴트 복사 생성자는 맴버 변수 대 멤버 변수의 복사를 수행한다.
IV. 깊은 복사를 하는 복사 생성자
- 디폴트 복사 생성자의 문제점
- #include <iostream>
- using namespace std;
- class Person
{
char *name;
char *phone;
int age;
public:
Person(char* _name, char* _phone,int _age);
~Person();
void ShowData();
}; - Person::Person(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;
} - Person::~Person()
{
delete []name;
delete []phone;
} - void Person::ShowData()
{
cout<<"name : "<<name<<endl;
cout<<"phone: "<<phone<<endl;
cout<<"age : "<<age<<endl;
} - int main()
{
Person p1("KIM","123-123",23);
Person p2 = p1;
return 0;
}
- 위의 소스를 실행 시켜보면 오류가 나게 된다 그 이유는 얕은 복사를 하고 있기 때문이다.
-
위의 그림이 얕은 복사이다. 위쪽의 소스가 위의 그림 처럼 되어 있는데 오류 나는 이유는 잘 실행되다가 소멸 과정(소멸은 생성이 나중에 된것 부터 소멸된다.)에서 p2가 사라지면 가리키는 값은 메모리에서 해제 되고 p1도 소멸할 때 메모리를 해제하려고보니 해제할 메모리 공간이 없어서 오류가 발생하게 되는 것 이다.
- 디폴트 복사 생성자는 얕은 복사를 하므로, 깊은 복사를 하도록 직접 복사 생성자를 제공해야 하낟.
- 깊은 복사
- #include<iostream>
- using namespace std;
- class Person
{
char *name;
char *phone;
int age;
public:
Person(char* _name, char* _phone,int _age);
Person(const Person& p);
~Person();
void ShowData();
}; - Person::Person(const Person &p)
{
name = new char[strlen(p.name)+1];
strcpy(name,p.name); - phone = new char[strlen(p.phone)+1];
strcpy(phone,p.phone);
age = p.age;
} - Person::Person(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;
}
Person::~Person()
{
delete []name;
delete []phone;
} - void Person::ShowData()
{
cout<<"name : "<<name<<endl;
cout<<"phone : "<<phone<<endl;
cout<<"age : "<<age<<endl; - }
- int main()
{
Person p1 ("kim","123-123",23);
Person p2 = p1; - p1.ShowData();
p2.ShowData();
}
- 위의 소스가 깊은 복사를 한 것이다. 명시적으로 복사 생성자를 만들었다.
V. 복사 생성자가 호출되는 시점
-
복사 생성자가 호출되는 시점은
- 기존에 생성된 객체로 새로운 객체를 초기화 하는 경우
- 함수 호출 시 객체를 값에 의해 전달하는 경우
- 함수 내에서 객체를 값에 의해 리턴하는 경우
- #include <iostream>
using namespace std; - class AAA
{
public:
AAA()
{
cout<<"AAA() 호출"<<endl;
}
AAA(const AAA& a)
{
cout<<"AAA(const AAA& a) 호출"<<endl;
}
}; - int main()
{
AAA obj1;
AAA obj2 = obj1;
return 0;
}
-
위의 소스는 호출되는 시점에서 첫번째인 기존에 생성된 객체로 새로운 객체를 초기화하는 경우이다.
- obj1은 기존에 이미 생성된 객체이고 obj2는 새롭게 생성하고자 하는 객체이다.
- void function(int a){}
int main()
{
int n =10;
function(n);
}
-
위의 같은 소느는 n을 10으로 초기화 하고나서 function으로 변수 n을 인자로 전달 할때 매개변수 a가 이 값을 복사하게 된다.
-
Call-By-Value에 의한 함수 호출 과정을 세분화 하면
- 매개 변수를 위한 메모리 공간 할당
- 전달 인자 값의 복사
-
- #include <iostream>
using namespace std; - class AAA
{
int val;
public:
AAA(int i)
{
val = i;
}
AAA(const AAA& a)
{
cout<<"AAA(const AAA& a)호출"<<endl;
val =a.val;
}
void ShowData()
{
cout<<"val : "<<val<<endl;
}
};
void funcion(AAA a)
{
a.ShowData();
}
int main()
{
AAA obj(30);
funcion(obj);
return 0;
}
-
위의 소스를 보면 function(obj)를 보면 obj가 가지고 있는 값을 a에 복사하는 것이다.
- 매개변수로 생성되는 객체의 복사 생성자가 호출되는 것이다.
- #include <iostream>
using namespace std; - class AAA
{
int val;
public:
AAA(int i)
{
val = i;
}
AAA(const AAA& a)
{
cout<<"AAA(const AAA& a)호출"<<endl;
val =a.val;
}
void ShowData()
{
cout<<"val : "<<val<<endl;
}
};
AAA function(void)
{
AAA a(10);
return a;
}
int main()
{
function();
return 0;
}
- 위의 소스는 main에서 function 함수를 호출 하고나서 function 함수 안에서 AAA a객체를 생성하고 나서 return a로 a객체 복사본을 리턴한다.
문제
5 -1
문제1
연습문제 4 -1의 3번 문제를 통해서 NameCard클래스를 정의하였다. 이 클래스도 생성자 내에서 메모리 공간을 동적 할당하고 있으며, 소멸자에서 이를 해제하고 있기 때문에 깊은 복사를 하는 복사 생성자가 필요한 상황이다. 이에 적절한 복사 생성자를 정의해 보기 바란다.
이 글은 스프링노트에서 작성되었습니다.
'2. C/C++ > 02. C++' 카테고리의 다른 글
007. 상속(Inheritance)의 이해 (0) | 2008.12.07 |
---|---|
006. static 멤버와 const 멤버 (0) | 2008.12.07 |
004. 클래스의 완성 (0) | 2008.12.07 |
003. 클래스의 기본 (0) | 2008.12.07 |
002. C 기반의 C++ 2 (0) | 2008.12.07 |