본문 바로가기
Working on

[Effective C++] 항목 9: 객체 생성 및 소멸 과정 중에는 절대로 가상함수를 호출하지 말자

by Warehaus 2021. 4. 9.

코드 작성하다가 아무 생각없이 실수할 것 같은 부분이라서 짧게나마 정리해 둔다.

[ Never call virtual functions during construction or destruction. ]

객체 생성 및 소멸 과정중에는 virtual 함수를 호출하면 절대 안된다는 내용이다.

 

 

예제 코드를 먼저 보자

class Circle {
public:
	Circle();
    
    virtual void drawCircle() const = 0;
    ...
};

Circle::Circle()
{
	...
	drawCircle(); // 생성 시 원을 그려준다
}

class Oval : Circle {
public:
	virtual void drawCircle() const; // 현재 타입의 원을 그린다.
    ...
};

Oval c;

마지막 Oval 임시객체를 생성하는 과정에서 생성자가 호출된다. 하지만 부모 클래스인 Circle의 생성자 (부모의 생성자)가 우선적으로 호출되며 이때, Oval의 drawCircle을 호출되지 않고 Circle의 drawCircle만 호출이 된다.

// 타원을 그려줘야 하는데 그냥 원을 그려버리는 것이다.

 

어찌보면 하위 클래스의 생성자는 아직 호출이 되지 않았으니 drawCircle의 호출을 기대하는 것은 어불성설일 수 있다.

 

하위 클래스에서 기대하고 있는 virtual 함수의 호출이 제대로 이뤄지고 있는지 확인하는 것은 상당한 노력을 필요로 한다.

 

이를 위해서 가상함수를 비 가상함수로 바꿔 주는 것도 방법이다.

// T : 원을 그리는 공식 (가정)
class Circle {
public:
	explicit Circle(const int x, const int y, T formula);
    
    void drawCircle(const int x, const int y, T formula) const;
    ...
};

Circle::Circle(const int x, const int y, T formula)
{
	...
	drawCircle(const int x, const int y,  T formula); // 생성 시 원을 그려준다
}

class Oval : Circle {
public:
 	//  circle에 필요한 변수를 넘겨서 초기화한다. 타원형 공식을 넘겨준다.
	Oval( params ) : Circle( x, y, f ) { ... }
    ...
private:
	T f;	
};

Oval c;

Circle 클래스에서 하위 클래스의 생성 작업을 수행할 수 있도록 공식을 넘겨줬다.

부모 클래스 생성자만 호출되더라도, Oval을 그려낼 수 있게 된다.

 

가상함수를 사용하는 경우 기본 클래스 부분이 하위 클래스로 넘어갈 수 없으므로, 필요한 정보를 하위 클래스 생성 시 상위 생성자로 올려서 필요한 초기화 작업을 진행하는 것을 권장한다.