3
#include <iostream>

template <class Derived>
class Base
{
public:
  void method1()
  {
    static_cast<Derived*>(this)->method1();
  }

  void method2()
  {
    static_cast<Derived*>(this)->method2();
  }
};

class Derived1: public Base<Derived1>
{
public:
  void method1()
  {
    std::cout << "Method 1 of Derived1 executed.\n";
  }
};

int main(int argc, char *argv[])
{
  Derived1 d1;
  d1.method1();
  d1.method2();
  return 0;
}

フォローアップの質問:このタイプを安全にするにはどうすればよいですか?つまり、誰かがmethod2の実装を忘れた場合、コンパイラにそれをキャッチしてもらいたいのです。実行時にこれが爆発するのは望ましくありません。

4

2 に答える 2

8

これが有効である理由は、このコードをインスタンス化した場合です。

void method2()
{
  static_cast<Derived*>(this)->method2();
}

の実装がDerivedない場合は、method2()本質的に栄光の自己再帰呼び出しになります。ここでの理由は、にDerived1、実際に、と呼ばれるメンバー関数method2、つまり基本クラスから継承されたものがあるためです。

私はこのコードを実行してみましたが、呼び出しmethod2によって自己再帰によるスタックオーバーフローが発生することを確認しました。

通常、CRTPは、基本クラス関数が同じ名前の派生クラス関数を呼び出さないようにすることで、これを回避します。そうすれば、派生クラスに特定の関数がない場合、呼び出しによってコンパイラエラーがトリガーされます。あなたの場合、関数自体が基本クラスから間接的に参照される可能性があるため、これは発生しません。

于 2011-01-18T06:23:10.603 に答える
2
  Derived1 d1;
  d1.method2();

は定義していDerived1ませんが、とにかくmethod2()継承して取得します。Baseそのため、コンパイルして実行します。d1.method2()実際にBase::method2()を呼び出します。これもまた自分自身を呼び出します。これは再帰的な呼び出しです。

于 2011-01-18T06:23:16.703 に答える