c++ - 关于CRTP静态多态的困惑

标签 c++ crtp

我正在努力研究 CRTP。周围有一些很好的资源,包括这个论坛,但我想我对静态多态性的基础知识有些困惑。查看以下维基百科条目:

template <class T> 
struct Base
{
    void implementation()
    {
        // ...
        static_cast<T*>(this)->implementation();
        // ...
    }

    static void static_func()
    {
        // ...
        T::static_sub_func();
        // ...
    }
};

struct Derived : public Base<Derived>
{
    void implementation();
    static void static_sub_func();
};

我知道这有助于我在派生类中有不同的 implementation() 变体,有点像编译时虚函数。但是,我的困惑是我认为我不能拥有像

这样的功能
void func(Base x){
    x.implementation();
}

因为 Base 是模板化的,所以我会使用普通的继承和虚函数,但我必须指定

func(Derived x)

或使用

template<class T> 
func(T x)

那么 CRTP 在这种情况下实际上给我带来了什么,而不是简单地在 Derived::Base 中直接隐藏/实现方法?

struct Base
{
    void implementation();
};

struct Derived : public Base
{
    void implementation();
    static void static_sub_func();
};

最佳答案

问题在于,关于 CRPT 的实际用途,将 CRTP 描述为“静态多态性”并没有真正的帮助或准确。多态性实际上就是让不同的类型实现相同的接口(interface)或契约;这些不同类型如何实现该接口(interface)与多态性是正交的。动态多态看起来像这样:

void foo(Animal& a) { a.make_sound();  } //  could bark, meow, etc

其中 Animal 是一个提供虚拟 make_sound 方法的基类,即 DogCat 等,覆盖。这是静态多态性:

template <class T>
void foo(T& a) { a.make_sound(); }

就是这样。您可以在恰好定义了 make_sound 方法的任何类型上调用 foo 的静态版本,而无需从基类继承。并且该调用将在编译时解析(即您无需为 vtable 调用付费)。

那么 CRTP 适合什么地方呢? CRTP 实际上根本与接口(interface)无关,因此与多态性无关。 CRTP 是为了让您更轻松地实现事情。 CRTP 的神奇之处在于它可以将事物直接注入(inject)到类型的接口(interface)中,并且完全了解派生类型提供的所有内容。一个简单的例子可能是:

template <class T>
struct MakeDouble {
    T double() {
        auto& me = static_cast<T&>(*this);
        return me + me;
};

现在任何定义加法运算符的类,也可以被赋予一个double方法:

class Matrix : MakeDouble<Matrix> ...

Matrix m;
auto m2 = m.double();

CRTP 完全是为了帮助实现,而不是接口(interface)。所以不要太在意它通常被称为“静态多态性”这一事实。如果您想要有关 CRTP 的用途的真正规范示例,请考虑 Andrei Alexandrescu 的现代 C++ 设计的第 1 章。不过,慢慢来 :-)。

关于c++ - 关于CRTP静态多态的困惑,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43821541/

相关文章:

c++ - 数组:仅将字符串数组的索引传递给 Int 数组的索引以供输出

c++ - 内存引用发送到双指针

c++ - 带有基类的 CRTP 试图获取派生类成员的返回类型 : invalid use of incomplete type

c++ - 如何将 CRTP 与可变参数模板一起使用?

c++ - 多级crtp如何将中级类型传递给上级

c++ - 如何通过不同的类将一个 vector 复制到另一个 vector

c++ - 将UTC时差转换成字符串boost

c++ - 代码块调试器在成员函数中时不显示类属性

c++ - 使用虚拟析构函数会使非虚拟函数进行 v 表查找吗?

c++ - 根据派生类字段指定基类模板参数