Yua*_* Wu 3 c++ polymorphism virtual-functions crtp static-polymorphism
我想知道如果我从不从基类调用函数(即虚拟调度),使用 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();
}
Run Code Online (Sandbox Code Playgroud)
work我发现如果我从接口child或通过接口调用虚函数CRTPMixin,反汇编代码是相同的,只有 static call。如果我调用该函数,Mixin& mixin = child就会发生虚拟调度,并且会为此操作生成更多指令。
我的问题是,如果我正在设计接口/混合类型结构,我只会使用派生类而不是基类来调用它,是否有任何情况 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();
}
Run Code Online (Sandbox Code Playgroud)