CRTP のポイントは、派生オブジェクトの型を仮想性なしで取得できるようにすることです。もしあなたがそうするなら
struct B { void foo() const; }
struct D : B { void foo() const; }
void bar(const B& x) { x.foo(); }
仮想関数ではないため、オブジェクトを渡すときではなく呼び出しbar
ます。呼び出されたい場合は、仮想機能または CRTPが必要です。B::foo
D::foo
D
foo
D::foo
最も単純な CRTP の場合:
template <typename>
struct B { void foo() const; }
struct D : B<D> { void foo() const; }
template <typename T>
void bar(const B<T>& x)
{
static_cast<const T&>(x).foo();
}
これは、オブジェクトD::foo()
に渡すときに呼び出されます。bar
D
ただし、代わりの CRTP トリックは、実装を提供することを強制しD
ます。foo
template <typename T>
struct B
{
void foo() const { static_cast<const T*>(this)->foo_impl(); }
// default implementation if needed
// void foo_impl() const { ... }
};
struct D : B<D> { void foo_impl() const { ... } };
template <typename T>
void bar(const B<T>& x) { x.foo(); }
B
ただし、 (foo
正しくディスパッチされるように)のテンプレート パラメータと、テンプレートbar
関数が必要です。
また、CRTP を使用しない場合は、仮想デストラクタを使用することをお勧めします。これにより、完全にインライン化される軽量クラスに不要なオーバーヘッドが追加される可能性があります。friend T
CRTP を使用すると、単純に保護されたデストラクタ ( C++0x ではプライベート デストラクタ + ) を記述できます。