2

CRTP中为了避免动态多态性,为了避免虚成员函数的开销并强加一个特定的接口,提出了以下解决方案:

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>. 如果您没有要定义的界面(正如您在问题的第二部分中建议的那样),那么首先不需要任何这些。

请注意,您不是像纯虚函数那样“强加”一个接口,而是提供一个接口。由于一切都在编译时解决,因此“强加”并不是一个强烈的要求。

于 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 回答