2

CRTP to avoid dynamic polymorphismでは、仮想メンバー関数のオーバーヘッドを回避し、特定のインターフェイスを課すために、次の解決策が提案されています。

template <class Derived>
struct base {
  void foo() {
    static_cast<Derived *>(this)->foo();
  };
};

struct my_type : base<my_type> {
  void foo() {}; // required to compile. < Don't see why
};

struct your_type : base<your_type> {
  void foo() {}; // required to compile. < Don't see why
};

ただし、派生クラスは定義を継承するため、コンパイルするための定義は必要ないようです (コードは、my_type::foo を定義しなくても正常にコンパイルされます)。実際、関数が提供されている場合、派生クラスを使用するときに基本関数は呼び出されません。

問題は、次のコード置換が受け入れられるかどうか (そして標準かどうか) です。

template <class Derived>
struct base {
  void foo() {
    // Generate a meaningful error if called
    (void)sizeof( Derived::foo_IS_MISSING );
  };
};

struct my_type : base<my_type> {
  void foo() {}; // required to compile.
};

struct your_type : base<your_type> {
  void foo() {}; // required to compile.
};

int main() {
  my_type my_obj;
  my_obj.foo(); // will fail if foo missing in derived class
}
4

4 に答える 4

4

このパターンの全体的なポイントは、私が理解している限り、引数を単純に渡すことができtemplate <typename T> base<T> &、インターフェイスが の (非仮想) 関数によって定義されていることbase<T>です。定義したいインターフェースがない場合(質問の2番目の部分で提案しているように)、そもそもこれは必要ありません。

純粋な仮想関数のようにインターフェイスを「課す」のではなく、インターフェイスを提供していることに注意してください。すべてがコンパイル時に解決されるため、「課す」ことはそれほど強い要件ではありません。

于 2011-07-20T19:10:26.537 に答える
2

foo置換コードでは、を「多態的に」呼び出すことはできませんbase<T>

于 2011-07-20T19:11:59.740 に答える
2

ただし、派生クラスは定義を継承するため、コンパイルするための定義は必要ないようです(コードはmy_type::foo を定義しなくても正常にコンパイルされます)。

C++ は怠け者です。実際に使用しない場合、base<my_type>::foo() を作成しようとしません。しかし、使おうとすると作成され、それが失敗するとコンパイル エラーが発生します。しかし、あなたの場合、 base<my_type>::foo() はうまくインスタンス化できます:

template <class Derived>
struct base {
  void foo() {
    static_cast<Derived *>(this)->foo();
  };
};

struct my_type : base<my_type> {};

void func() {
    my_type m;
    static_cast<base<my_type>& >(m).foo();
}

うまくコンパイルされます。コンパイラが static_cast(this)->foo() を提示されると、my_type でアクセス可能な foo() を見つけようとします。それは base<my_type>::foo() という名前で、パブリックに継承されたクラスから公開されています。base<my_type>::foo() が base<my_type>::foo() を呼び出すと、無限再帰が発生します。

于 2011-07-20T19:30:31.473 に答える
0

いいえ、次の状況を想像してください。

template <typename T>
void bar(base<T> obj) {
   obj.foo();
}

base<my_type> my_obj;
bar(my_obj);

Base の foo が my_type の代わりに呼び出されます...

これを行うと、エラー メッセージが表示されます。

template <class Derived>
struct base {
  void foo() {
    sizeof(Derived::foo);
    static_cast<Derived *>(this)->foo();
  };
};

しかし、GCC のみでテストされた GCC 以外のコンパイラでこれがどのように機能するかはわかりません。

于 2011-07-20T19:09:26.900 に答える