동적 바인딩, 런타임에 성격이 결정되는 것
반대는 static binding이 있으며, static binding은 컴파일 시간에 성격이 결정되어 런타임 시간이 짧다.
CRTP, 클래스 X가 X자신을 템플릿 인자로 사용하여 인스턴스화 되는 클래스 템플릿으로 파생됨.
// The Curiously Recurring Template Pattern (CRTP)
template <typename T>
struct base
{
// ...
};
struct derived : base<derived>
{
// ...
};
개체가 초기화되는 동안 derived class의 가상 함수를 호출하는 것이 좋은 경우가 있다.
언어는 이러한 방법이 위험하기 때문에 이러한 일이 발생하지 않도록 금지한다.
가상 함수가 구성 중인 개체의 데이터 멤버에 액세스하지 않는 경우 문제가 없지만, 이를 보장할 일반적인 방법이 없다.
가능한 접근 방식은 두 가지가 있다.
객체 생성과 상태 초기화를 분리한다. 이러한 분리가 항상 가능한 것은 아니다.
class Base {
public:
void init(); // May or may not be virtual.
...
virtual void foo(int n) const; // Often pure virtual.
virtual double bar() const; // Often pure virtual.
};
void Base::init()
{
... foo(42) ... bar() ...
// Most of this is copied from the original Base::Base().
}
class Derived : public Base {
public:
Derived (const char *);
virtual void foo(int n) const;
virtual double bar() const;
};
class Base {
public:
template <class D, class Parameter>
static std::unique_ptr <Base> Create (Parameter p)
{
std::unique_ptr <Base> ptr (new D (p));
ptr->init ();
return ptr;
}
};
int main ()
{
std::unique_ptr <Base> b = Base::Create <Derived> ("para");
}
Curiously Recurring Template Pattern idiom을 사용한다.
class Base {
};
template <class D>
class InitTimeCaller : public Base {
protected:
InitTimeCaller () {
D::foo ();
D::bar ();
}
};
class Derived : public InitTimeCaller <Derived>
{
public:
Derived () : InitTimeCaller <Derived> () {
cout << "Derived::Derived()" << std::endl;
}
static void foo () {
cout << "Derived::foo()" << std::endl;
}
static void bar () {
cout << "Derived::bar()" << std::endl;
}
};