지속가능티끌/C . C++2015. 12. 28. 19:51

 

 

개요. C++ 클래스 생성자 기초지식.

 

C++ 클래스의 생성자 관련 기초 지식들 정리.

 

1. 클래스의 디폴트 생성자.

2. 클래스의 복사 생성자.

3. 디폴트 복사 생성자는 shallow copy 수행함. Deep Copy 원하면 복사생성자 명시적으로 정의하고 복사생성자 내에 값복사코드 추가할것.

 

 

 

 

 

 

클래스의 디폴트 생성자.

   

1. 컴파일 과정에서 자동으로 추가되는 생성자 를 디폴트 생성자라 한다. 디폴트 생성자는 인자없고 디폴트생성자 내에서 처리하는것도 없다.

 

2. 코드 작성시 클래스에 생성자를 구현하지 않은 경우, 컴파일 단계에서 클래스에 디폴트 생성자가 자동삽입되고 클래스 개체 생성시 디폴트 생성자가 실행된다. 

참고 : 소멸자를 명시적으로 정의하지 않은 경우에도 컴파일 단계에서 자동으로 디폴트 소멸자가 추가됨.

 

3. 코드 작성시 클래스에 생성자(인자있는 생성자든 인자 없는 생성자든)를 명시적으로 구현한 경우에는 상기2 처럼 자동 삽입되는 "디폴트 생성자"는 만들어지지 않는다.

 

4. 상기 3과 같은 말이지만,.. 클래스에 인자 있는 생성자를 정의한 경우 컴파일러가 자동으로 만드는 디폴트 생성자 만들어지지 않음.

 

 아래 (가)와 (나)의 클래스는 컴파일하고 나면 완전히 동일한 것임.

즉, (가)는 생성자를 정의하지 않았고, (나)는 인자없는 생성자를 정의하였고, 생성자내에서 아무런 처리수행하지도 않는것으로 만든것임. (가)는 컴파일과정에서 인자없는 생성자를 자동 추가 하므로 (나)와 동일한 것이 된다.

 

(다)의 클래스에는 인자있는 생성자가 정의되어있는데, 이 경우 컴파일과정에서 디폴트생성자(인자 없는 생성자) 만들지 않음.

(다) 처럼 인자있는 생성자뿐만 아니라 인자없는 생성자가 필요한 경우 (라) 처럼 인자없는 생성자를 명시적으로 정의하면됨. 즉, 생성자도 함수의 오버로딩과 동일하게 같은 이름의 함수명으로 여러 개 정의 가능. 개체생성시 인자있는것 호출하든 인자 없는것 호출하든 선택한 것이 실행된다.

 (가)

 (나)  (다)

 (라)

class A

{

public:

 

 class A

{

public:

  A(){}  // 인자없는 생성자 명시했음.

}

 class A

{

public:

 A(int a) {} // 인자있는 생성자.

}

 class A

{

public:

 A() {}      // 인자없는

 A(int a) {}// 인자있는

}

 

 

 

 

 

클래스의 복사 생성자.

 

 

복사 생성자

 

복사 생성자 정의  : 클래스 자신과 동일한 클래스 개체를 인자로 받을 수 있는 생성자. 아래 예의 코드에서의 생성자를 복사 생성자라 한다. 

생성자의 인자로 "클래스A 개체의 상수형 레퍼런스" 를 전달가능함.

 

복사 생성자 기능 : 클래스 생성시 동일클래스의 다른 개체의 멤버변수가 복사된것으로 생성 하게됨.

 

class A

{

public:

A(const A& a){} // 복사 생성자임.

}

 

 

복사 생성자 이용한 개체 생성예.

아래예의 파랑색 코드처럼 복사생성자를 사용하게된다. 클래스A 개체 a2 를 생성하는데 동일클래스A 개체 a1을 클래스A 생성자의 인자로 전달하면서 a2를 생성하고 있다.

 

main

{

 A a1;

 A a2(a1); // 클래스A 개체 a2 생성시 클래스A 개체 a1 을 생성자의 인자로 전달하고 있다.

 

}

 

 

 

디폴트 복사 생성자.

 

클래스 정의시 위의 예와 같은 복사생성자를 정의하지 않은 경우 컴파일러가 자동으로 복사 생성자를 추가하게 된다. 자동으로 추가되는 복사생성자를 "디폴트복사 생성자" 라고 한다. 디폴트 복사 생성자 만으로도 클래스 멤버변수의 복사가능함.

 

디폴트 복사 생성자로 이뤄지는 복사는 Shallow Copy(얕은 복사).

별도로 우리의 클래스에 복사생성자를 정의하지 않아도 컴파일 단계에서 자동으로 삽입되는 복사 생성자 만으로도 클래스의 멤버변수의 복사가 가능하므로 매우 편리하다.

그러나, 클래스 멤버 변수로 포인터 변수가 있는 경우 디폴트복사생성자로 신규개체 a2 생성하면서 a1개체를 복사하면서 생성하면, a2 개체의 포인터변수에는 a1개체의 포인터변수의 값 즉 "주소"만 복사된다. 주소에 있는 데이터가 복사되는것 아님.

멤버변수에 저장되어있는 것이 그대로 복사된다는 점에서는 정상적인 멤버변수의 값을 복사한것임.

상기와 같은 복사를 Shallow Copy라고 하며, 디폴트복사생성자는 Shallow Copy를 수행한다.

 

Deep Copy

상기 Shallow Copy 처럼 포인터변수의 주소만 복사되는것이 아닌 주소에 있는 "데이터"도 복사되는 것을 Deep Copy라고 한다. Deep Copy를 위한 자동화된 뭔가가 있는건 아니고 개발자가 직접 코딩해줘야 한다. 코드에서 포인터변수에 있는 데이터까지 복사해오기 위하여 "메모리 동적생성" 하고 데이터 복사처리를 하는 게 요점. 

Deep Copy 를 코드에서 구현하려면 복사생성자를 명시적으로 정의하고, 복사생성자 내에서 포인터변수들의 값복사 되도록 직접 코드 추가해야한다. 예를들면 아래 파랑색코드 처럼 값복사 되도록 직접 코딩한다.

참고 : 생성자 내에서 new 를 이용하여 메모리 동적할당한 경우 소멸자에서 동적할당한 메모리 delete  코드 추가할것. 아래 붉은색 글자.

 

class A

{

public:

char* p_ch; //포인터변수.

A(const A& a) // 복사 생성자임.

{

 p_ch = new char[strlen(a.p_ch)+1];

strcpy(p_ch,a.p_ch); //여기서 포인터 변수가 지시하는 주소의 값복사 이뤄짐.

}

 

~A() // 소멸자.

{

 delete []p_ch; // 생성자에서 동적생성한 메모리 해제처리.

}

}

 

 

 

 

 

 본 글이 포함된 상위 정리 장소.

 

 Visual Studio/VC++/C/C# 활용정리 -> http://igotit.tistory.com/11

 

 

///528.

 

 

Posted by 리치굿맨

댓글을 달아 주세요