C언어

c++ 공부 요점정리 11

뮹실이 2013. 11. 21. 22:08








1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
// =====================================================
// 26 디폴트 복사 생성자
// =====================================================
//
// 디폴트 복사 생성자의 문제점
// : 얕은 복사에 의한 메모리 참조 오류
//
// 컴파일시 에러가 발생하는 예제
//
#include<iostream>
using std::cout;
using std::endl;

class Person
{
	char *name;
	char *phone;
	int age;
public:
	Person(char* _name, char* _phone, int _age);
	~Person();
	// 복사 생성자가 선언되지 않았기 때문에
	
	// 멤버 대 멤버를 복사하는
	
	// 디폴트 복사 생성자를 자동으로 제공한다.
	
	// 자동으로 추가될 디폴트 복사 생성자의 내용은
	
	// 다음과 같을 것이다.
	//
	// Person(const Person& p){
	// 	name = p.name;
	// 	phone = p.phone;
	// 	age = p.age;
	// }
	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", "013-333-5555", 22);
	Person p2=p1; // 이문장은 묵시적으로
	// person p2(p1);으로 변환되어 사용된다.
	//
	// p2의 멤버에 복사되는 p1 멤버의 값은
	//
	// 힙영역에 동적할당된 메모리공간의 주소값이다.
	//
	// 즉, p1과 p2가 같은 동적메모리 공간을 가리키는
	//
	// 포인터이다.
	//
	// 이 상황까지는 문제가 되지 않지만
	//
	// 소멸자가 호출될때 문제가 발생한다.
	
	// main 함수가 끝남과 동시에 p1, p2 객체가
	
	// 사라지기 위해서 소멸자가 호출되는데
	
	// 소멸자에서는
	
	// name과 phone이라는 포인터가 가리키는 문자열을
	
	// 해제한다.
	
	// (객체가 사라지는 순서는 객체가 생성된 순서의 
	
	// 역순이다.
	
	// 스택이라는 메모리의 특성때문)
	
	// p2 객체가 사라질때 동적할당된 메모리 공간이 
	
	// 해제된다.
	
	// 이제 p1객체가 사라질때 p1 객체가 가리키는 
	
	// 메모리 공간을 해제해야하는데 p2가 사라질때
	
	// 이미 사라졌기 때문에 문제가 된다.
	
	// 즉 하나의 메모리 공간을 두번 해제 
	
	// 하려 하기 때문에 문제가 발생한다.
	
	// 이러한 복사 형태를 얕은 복사라 한다.
	
	// 즉, p1 객체를 복사하면
	
	// p1이 가리키는 동적메모리의 주소만 복사하는것
	
	// 깊은 복사는 
	
	// p1 객체를 복사 했을 때 
	
	// p1이 가리키는 동적메모리의 값을 다른 동적 메모리에
	
	// 할당해 p2가 그 동적 메모리를 가리키도록하는 복사
	
	// 디폴트 복사 생성자는 깊은 복사를 하도록 제공되는게
	
	// 아니라 얕은 복사를 하도록 제공되어진다.
	
	//
	// 생성자에서 동적할당을 할 경우 
	
	// 소멸자에서 해제를 해야한다.
	
	// 그리고 객체 생성을 하는 과정에 있어서
	
	// 디폴트 복사 생성자를 호출하면
	
	// 얕은 복사를 하기 때문에 문제가 발생한다.
	
	// 따라서 깊은 복사를 하도록 복사생성자를
	
	// 선언해줘야한다.(생성자에서 동적할당을 할 경우)
	
	//
	
	// 즉 생성자에서 동적할당을 할 경우
	
	// 소멸자와 복사생성자(사용자 정의)를 선언해줘야한다.
	
	// 다음과 같은 깊은 복사를 하도록 
	
	// 복사생성자를 선언해야한다.
	
	//
	//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;
	//}
	//
	// strlen은 실질적인 문자열의 길이를 리턴하기 때문에
	
	// 문자열의 끝을 나타내는 NULL문자를 고려하기 위해서
	
	// + 1 을 추가해준다
	
	return 0;
}