[C++/Syntax] Class 2

Con(De)structor/생성(소멸)자
Copy-constructor/복사 생성자

C++의 Class는 접근제어 뿐 아니라 여러가지 기능을 지원한다.


생성자

생성자는 Class와 동일한 이름을 가지고 객체가 생성될 때 호출된다.
Class 첫번째 글에 Code 2-1를 살짝 수정해보자.

class Person {
private:
	char name[10];
	int pox, poy;
public:
	Person(const char name[], int pox, int poy) {
		strcpy(this->name, name);
		this->pox = pox;
		this->poy = poy;
	}

	void ShowPostion() {
		std::cout << pox << " " << poy << std::endl; 
		return;
	}
	void work() {
		pox++;
		poy++;
	}
};

int main(){
	Person man("man", 10, 10);
	man.ShowPostion();
	man.work();
	man.ShowPostion();
	return 0;
}

public아래 Person(…)이 생성자다.
기존의 코드에선 초기화를 해주는 함수를 따로 지정해 줫지만,
생성자를 선언한 후엔 man(“man”, 10, 10)으로 생성자를 호출해 초기화 해주는 것을 볼 수 있다.

물론 private 안에서도 생성자를 선언할 수 있다 하지만 private 안에 있는 생성자는 class내에서 밖에 접근하지 못한다.

 

++멤버 이니셜라이저 (Member initializer)

Class안의 함수를 호출할 때 Class로 선언된 변수를 초기화 할 수 있는 방법이다 아래 클래스를 보자.

class Trip {
private:
	Person man;
	Person woman;
	int number;
public:
	Trip(const char name1[], const char name2[], const int pox1, const int poy1, const int pox2, const int poy2)
		:man(name1, pox1, poy1), woman(name2, pox2, poy2), number(pox1)
	{
		// Code
	}
};

Trip이란 class 안에서 선언된 Person class들을 초기화 할 때,
:man(name1, pox1, poy1), woman(name2, pox2, poy2)이처럼 초기화 해줄 수 있다.
또한 number(pox1)처럼 상수도 같은 방식으로 초기화 해줄 수 있다.

 

소멸자

소멸자는 생성자와 정 반대 이다.
class가 사라질 때 호출 되는 함수이다. 표현식은 ~ClassName(){}으로 표현한다.

class Person {
private:
	char name[10];
	int pox, poy;
	char * dump;
public:
	Person(const char name[], int pox, int poy) {
		strcpy(this->name, name);
		this->pox = pox;
		this->poy = poy;
		this->dump = new char[pox];
	}
	void ShowPostion() {
		std::cout << pox << " " << poy << std::endl; 
		return;
	}
	void work() {
		pox++;
		poy++;
	}
	~Person() {
		delete[]dump;
		std::cout << "Call Desconstructor" << std::endl;
	}
};

int main(){
	Person man("man", 10, 10);
	man.ShowPostion();
	man.work();
	man.ShowPostion();
	return 0;
}

~Person() { .. } 에서 생성자에서 생성된 dump 객체를 delete한다.
이렇게 깜빡하고 비우지 못한 메모리를 Class 사용이후에 자동으로 비울 수 있게 해준다.

 

복사 생성자

뭔가 했다 그리 어려운게 없다.

만약 Person man1("man1", 10, 10)이렇게 생성한 객체를 Person man2=man1이렇게 직접 복사해 넣는다고 해보자
그러면 자동적으로 생성된 복사 생성자가 Class의 각각의 변수를 잘 넣어주는 기본 복사 생성자를 만들어 넣어준다.

하지만 이를 직접 변경할 때는 생성자를 오버라이트하여 아래와 같이 설정해주면 된다.
Person(Person copy){ ... }

깊은 복사/ 얕은 복사..?

이러한 이야기가 나오게 된건 위에 자동으로 만들어진 복사 생성자를 사용할 때 문제가 발생하기 때문이다.

class Person {
private:
	[Skip]
	char * dump;
public:
	Person(const char name[], int pox, int poy) {
		[Skip]
		this->dump = new char[pox];
	}
	void ShowPostion() {
		[Skip]
	}
	void work() {
		[Skip]
	}
	~Person() {
		delete[]dump;
		std::cout << "Call Desconstructor" << std::endl;
	}
};

int main(){
	Person man1("man", 10, 10);
	Person man2 = man1;
	[Skip]
	return 0;
}

 위 소스코드를 실행하면 “Call Desconstructor”가 하나만 나오고 에러가 출력되는데,
이는 Person Class안에 dump 포인터가 가르키는 대상이 없어졋기 때문이다.

일반적으로 기본 복사 생성자는 *(포인터) 값을 복사하고, 포인터가 가르키는 *dump 값은 복사하지 않기 때문이다.
이미 man1의 소멸자가 delete[]dump를 했는데 복사된 man2에서 delete[]dump를 하니 에러가 발생하는 것이다.

이를 위해 깊은 복사. 즉 * 가 가르키는 대상인 *dump를 복사해서 넣어주는 과정을 정의해주는 것을 “깊은 복사”라고 한다.

카테고리C++

글의 문제가 있다면 댓글을 달아 주세요.

이 사이트는 스팸을 줄이는 아키스밋을 사용합니다. 댓글이 어떻게 처리되는지 알아보십시오.