我想知道如果我从不从基类调用函数(即虚拟分派(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/