#cpp pure virtual call - 언제 derived type이 되는가?
class Base
{
public:
Base()
{
WriteLine("Base::Base()", typeid(*this).name());
f();
}
void f()
{
WriteLine("Base::f()", typeid(*this).name());
virt();
}
protected:
virtual void virt() { WriteLine("Base::virt()"); }
};
class Derived : public Base
{
public:
Derived()
{
WriteLine("Derived::Derived()", typeid(*this).name());
f();
}
protected:
virtual void virt() { WriteLine("Derived::virt()"); }
};
// main
Derived d;
Base::Base() - class Base
Base::f() - class Base
Base::virt()
Derived::Derived() - class Derived
Base::f() - class Derived
Derived::virt()
pure virtual call 문제가 생기는 이유를 알아보기에 앞서 먼저 생성자에서 가상 함수를 호출할 때 어떻게 동작하는지 살펴봐야 한다. 3번째 줄을 눈여겨 보자. 왜 Derived::virt()
가 아니라 Base::virt()
가 호출됐을까?
원인은 c++에서 최종 타입이 되는 시기가 상식적이지 않기 때문이다. Derived 오브젝트를 생성할 때, 부모가 있기 때문에 Base::Base()
를 먼저 호출하게 되는데, 이때 타입은 Base이다. 그래서 Derived::virt()
가 아니라 Base::virt()
가 호출됐다. 그럼 언제 Derived 타입이 되는가? Base::Base()
호출이 끝나고 Derived::Derived()
가 호출될 때, 그제야 Derived 타입이 된다.
//virtual void virt() { WriteLine("Base::virt()"); }
virtual void virt() = 0;
R6025 - pure virtual function call
자, 이제 Base 클래스에 있는 virt()
함수를 pure virtual 함수로 바꿔보자. 위에서 봤던 대로 생성자에서 가상 함수를 호출할 때(거쳐서 호출), Base:virt()
가 호출된다. Base:virt()
는 pure virtual function. 짠~ 그래서 프로그램이 실패하게 되는 것.
이런 언어 특성 때문에 Mock Object를 만들 때 많이 사용하는 Extract and override factory method 리팩토링 방법을 쓰지 못하고 Abstract Factory pattern과 같은 다른 방법을 사용해야 한다.