블로그 이미지
Kanais
Researcher & Developer 퍼즐을 완성하려면 퍼즐 조각들을 하나 둘씩 맞춰나가야 한다. 인생의 퍼즐 조각들을 하나 둘씩 맞춰나가다 보면 인생이란 퍼즐도 완성되는 날이 오려나...?

calendar

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

Notice

2015. 4. 16. 11:42 Programming/C/C++

참고 서적 : Effective C++ - Meyers / 곽용재 옮김 / 피어슨에듀케이션코리아

 

2. 생성자, 소멸자 및 대입 연산자

생성자는 새로운 객체를 메모리에 만드는 데 필요한 과정을 제어하고 객체의 초기화를 맡는 함수이고, 소멸자는 객체를 없앰과 동시에 그 객체가 메모리에서 적절히 사라질 수 있도록 하는 과정을 제어하는 함수이며, 대입 연산자는 기존의 객체에 다른 객체의 값을 줄 때 사용하는 함수입니다. 잘 만들어진 클래스라면 반드시 갖고 있게 되는 대표적인 이 함수들을 어떻게 하면 멋지게 모아둘 수 있을까요? 그 ‘어떻게 하면’이 바로 이번 장에서 다루고자 하는 것입니다.

 

항목 5 : C++가 은근슬쩍 만들어 호출해 버리는 함수들에 촉각을 세우자

C++의 어떤 멤버 함수는 여러분이 클래스 안에 직접 선언해 넣지 않으면 컴파일러가 저절로 선언해 주도록 되어 있습니다. 바로 복사 생성자(copy constructor), 복사 대입 연산자(copy assignment operator), 그리고 소멸자(destructor)인데, 좀더 자세히 말하면 이때 컴파일러가 만드는 함수의 형태는 모두 기본형입니다. 게다가, 생성자조차도 선언되어 있지 않으면 역시 컴파일러가 기본 생성자를 선언해 놓습니다. 이들은 모두 public 멤버이며 inline 함수입니다. 다음과 같이 쓰면

class Empty

{

};

다음과 같이 쓴 것과 근본적으로 대동소이합니다.

class Empty

{

public:

       Empty() {...}                           // 기본생성자

       Empty(const Empty& rhs) {...}           // 복사생성자

       ~Empty() {...}                          // 소멸자

       Empty& operator=(const Empty& rhs) {...}// 복사대입연산자

};

이들은 꼭 필요하다고 컴파일러가 판단할 때만 만들어지도록 되어 있지만, 필요한 조건이 그리 대단한 것도 아닙니다. 이들이 만들어지는 조건을 만족하는 코드는 다음과 같습니다.

Empty e1;           // 기본생성자, 그리고소멸자

Empty e2(e1);        // 복사생성자

e2 = e1;            // 복사대입연산자

기본 생성자와 소멸자가 하는 일은 일차적으로 컴파일러에게 “배후의 코드”를 깔 수 있는 자리를 마련하는 것입니다. 기본 클래스 및 비정적 데이터 멤버의 생성자와 소멸자를 호출하는 코드가 여기서 생기는 거지요. 이때 소멸자는 이 클래스가 상속한 기본 클래스의 소멸자가 가상 소멸자로 되어 있지 않으면 역시 비가상 소멸자로 만들어진다는 점을 꼭 짚고 넘어가야겠습니다(소멸자의 가상성을 기본 클래스로부터 물려받는 경우에 말이죠).

컴파일러가 몰래 만들어낸 복사 생성자/복사 대입 연산자가 하는 일은 아주 단순합니다. 원본 객체의 비정적 데이터를 사본 객체 쪽으로 그냥 복사하는 것이 전부이지요. 이해를 돕기 위해 아래 예제를 준비해 보았습니다.

class NamedObject

{

private:

       string nameValue;

       int ageValue

public:

       NamedObject(string name);

       NamedObject(String name, int age);

}

이 NameObject 클래스 안에는 생성자가 선언되어 있으므로, 컴파일러는 기본 생성자를 만들어내지 않을 것입니다.

반면, 복사 생성자나 복사 대입 연산자는 NameObject에 선언되어 있지 않기 때문에, 이 두 함수의 기본형이 컴파일러에 의해 만들어집니다(필요하다면요).

 

참조자를 데이터 멤버로 갖고 있는 클래스에 대입 연산을 지원하려면 여러분이 직접 복사 대입 연산자를 정의해 주어야 합니다. 데이터 멤버가 상수 객체인 경우에도 C++ 컴파일러가 비슷하게 동작하니 꼭 주의하세요.

복사 대입 연산자를 private로 선언한 기본 클래스로부터 파생된 클래스의 경우, 이 클래스는 암시적 복사 대입 연산자를 가질 수 없습니다. 컴파일러가 거부해 버리니까요.

 

이것만은 잊지 말자!

l  컴파일러는 경우에 따라 클래스에 대해 기본 생성자, 복사 생성자, 복사 대입 연산자, 소멸자를 암시적으로 만들어 놓을 수 없습니다.

posted by Kanais