c++ - CRTP 与作为接口(interface)或 mixin 的虚拟函数

标签 c++ polymorphism virtual-functions crtp static-polymorphism

我想知道如果我从不从基类调用函数(即虚拟分派(dispatch)),使用 CRTP 是否比虚函数多态性有任何好处?

这里是示例代码。反汇编可以在https://godbolt.org/z/WYKaG5bbG找到.

struct Mixin {
  virtual void work() = 0;
};

template <typename T>
struct CRTPMixin {
  void call_work() {
    static_cast<T*>(this)->work();
  }
};

struct Parent {};
struct Child : Parent, Mixin, CRTPMixin<Child> {
  int i = 0;
  void work() override {
    i ++;
  }
};

Child child;
Mixin& mixin = child;


int main() {
  child.work();
  mixin.work();
  child.call_work();
}

我发现如果我从child调用虚函数work或者通过CRTPMixin接口(interface)调用,反汇编代码是相同的,仅静态调用。如果我在 Mixin& mixin = child 上调用该函数,则会发生虚拟调度,并且会为此操作生成更多指令。

我的问题是,如果我正在设计接口(interface)/混合类型结构体,我只会使用派生类而不是基类来调用它,是否有任何情况下 CRTP 会比虚拟函数方法受益更多?

谢谢!

最佳答案

如果您始终仅从派生类调用,那么 CRTP 比虚函数要好得多。 直接调用函数不仅比通过虚拟调度更快,而且还允许函数内联和其他优化。

从 C++23 开始,我们可以比以前更简单地执行 CRTP。示例来自 https://en.cppreference.com/w/cpp/language/crtp

#include <cstdio>
 
#ifndef __cpp_explicit_this_parameter // Traditional syntax
 
template <class Derived>
struct Base { void name() { (static_cast<Derived*>(this))->impl(); } };
struct D1 : public Base<D1> { void impl() { std::puts("D1::impl()"); } };
struct D2 : public Base<D2> { void impl() { std::puts("D2::impl()"); } };
 
void test()
{
    Base<D1> b1; b1.name();
    Base<D2> b2; b2.name();
    D1 d1; d1.name();
    D2 d2; d2.name();
}
 
#else // C++23 alternative syntax; https://godbolt.org/z/KbG8bq3oP
 
struct Base { void name(this auto& self) { self.impl(); } };
struct D1 : public Base { void impl() { std::puts("D1::impl()"); } };
struct D2 : public Base { void impl() { std::puts("D2::impl()"); } };
 
void test()
{
    D1 d1; d1.name();
    D2 d2; d2.name();
}
 
#endif
 
int main()
{
    test();
}

关于c++ - CRTP 与作为接口(interface)或 mixin 的虚拟函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/75079450/

相关文章:

java - List<Dog> 是 List<Animal> 的子类吗?为什么 Java 泛型不是隐式多态的?

c++ - 是否有可能有一个继承最终函数但创建相同函数(而不是重写)的派生类?

c++ - 在 Arduino 中使用虚拟方法

c++ - 构建/销毁过程中的虚拟调用

C++ 使用指针复制 char*

c++ - 从文件中读取数据并进行操作

c++ - 循环一个函数

c++11 - C++11 中的最终非多态类

c++ - 在 Objective-C++ 中将 CFTypeRef 转换为 Boolean

Haskell刚性类型变量错误