[Effective C++] #9 가상 함수를 호출하는 생성자, 소멸자
Scott Meyers의 "Effective C++"를 통해, C++ 구현에 필요한 개념들을 이해하고, 기록하기 위함입니다. 해당 항목은 2장 "생성자, 소멸자 및 대입 연산자", 항목 9 "객체 생성 및 소멸 과정 중에는 절대로 가상 함수를 호출하지 말자"에 해당하는 내용입니다.
생성자 내부의 가상 함수
class 기본클래스 {
public:
기본클래스 ();
virtual void 가상함수 () const = 0;
...
};
기본클래스::기본클래스 () {
가상함수 ();
}
class 파생클래스: public 기본클래스 {
public:
virtual void 가상함수 () const;
...
};
// 파생클래스 객체 생성
파생클래스 pc;
위 예제 코드는 기본 클래스를 상속하는 파생 클래스 객체를 생성하고 있습니다. 이때, 기본 클래스의 생성자를 살펴보면, 내부에서 가상 함수를 호출하고 있습니다. 여기서 문제가 발생하죠. 알다시피, 새로운 파생 클래스 객체 생성을 위해 파생 클래스의 생성자보다 기본 클래스의 생성자가 선제되어야 합니다. 따라서, 객체 타입이 파생 클래스임에도 불구하고, 기본 클래스의 생성자가 선제되어 기본 클래스의 가상 함수가 호출됩니다. 기본 클래스의 생성자가 호출되는 동안에, 가상 함수는 절대 파생 클래스 쪽으로 내려가지 않는다고 합니다. 그 이유는 기본 클래스의 생성자가 호출되는 시점에 파생 클래스의 데이터 멤버들은 초기화되 않은 상태입니다. 그러므로, 가상 함수가 기본 클래스에서 파생 클래스로 내려가게 되면 아직 초기화되지 않은 데이터 멤버들을 다루게 되어 큰 문제가 생기게 되겠죠.
해결 방법, 가상 함수 -> 비 가상 함수
class 기본클래스 {
public:
explicit 기본클래스 (const std::string& 정보);
void 비가상함수 (const std::string& 정보) const;
...
};
기본클래스::기본클래스 (const std::string& 정보){
...
비가상함수(정보);
}
class 파생클래스: public 기본클래스 {
public:
파생클래스 ()
: 기본클래스(정보생성함수(...)){...}
...
private:
static std::string 정보생성함수 (...);
};
문제 해결 방법을 제시하는 예제 코드입니다. 먼저, 가상 함수를 비 가상 함수로 바꿧습니다. 따라서, 기본 클래스의 생성자는 안전하게 비 가상 함수를 호출할 수 있습니다. 그리고 파생 클래스의 생성자는 기본 클래스에서 필요로 하는 정보들을 생성하여 넘겨주죠. 가상 함수를 통해 기본 클래스에서 파생 클래스로 내려올 수 없는 상황을 반대로 필요한 초기화 정보를 파생 클래스에서 기본 클래스로 올려주어 에러를 발생시키지 않는 과정으로 탈바꿈합니다.
기본 클래스의 생성자는 파생 클래스의 생성자보다 먼저 호출됩니다.
'언어 > Effective C++' 카테고리의 다른 글
[Effective C++] #11 중복 참조와 자기 대입 연산자 (0) | 2022.01.12 |
---|---|
[Effective C++] #10 대입 연산자와 *this의 참조자 (0) | 2022.01.12 |
[Effective C++] #8 소멸자가 던지는 예외 (0) | 2022.01.10 |
[Effective C++] #7 기본 클래스와 가상 소멸자 (0) | 2022.01.07 |
[Effective C++] #6 사용자 정의 기본 멤버 함수 (0) | 2022.01.07 |