코드 작성하다가 아무 생각없이 실수할 것 같은 부분이라서 짧게나마 정리해 둔다.
[ 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을 그려낼 수 있게 된다.
가상함수를 사용하는 경우 기본 클래스 부분이 하위 클래스로 넘어갈 수 없으므로, 필요한 정보를 하위 클래스 생성 시 상위 생성자로 올려서 필요한 초기화 작업을 진행하는 것을 권장한다.
'Working on' 카테고리의 다른 글
[Effective C++] operator= 에서는 자기대입에 대한 처리가 빠지지 않게하자 (0) | 2021.05.19 |
---|---|
[Effective c++] 항목 10: 대입 연산자는 *this 참조 반환하게 하자. (0) | 2021.05.12 |
NVIDIA NVTAGS ( Topology-Aware GPU Selection ) 메뉴얼 읽기 - 1 (0) | 2021.04.21 |
Getting started with MIG (0) | 2021.03.21 |
Understanding the concepts of Multi-instance GPU (MIG) (0) | 2021.03.20 |