如果已经有人问过这个问题,请提前道歉,因为您可能可以从标题中看出,我不太确定如何以可搜索的方式表达这个问题。
假设我有一个抽象类和派生类,如下所示:
class base {
public:
virtual void pure_func() = 0;
virtual void virt_func() {
// virtual call
pure_func();
}
};
class derived : public base {
public:
// final method
void pure_func() final {
// ... do something ...
}
};
我想知道是否有一种方法可以继承
virt_func
的实现,以便对 pure_func
的调用是非虚拟的。我知道,如果类型是静态已知的,常见的编译器优化是跳过 vtable 查找,但由于此实现是在基类中编写一次,我相信这需要虚拟调用。我或多或少地问是否有一种方法可以为每个派生类重新实现抽象基类方法,以便优化编译器可以更好地处理虚拟调用(例如,跳过虚函数表查找)。我从未听说过有这样的优化。
我曾经想过但由于各种原因而决定放弃的事情:
我问这个主要是出于教育目的。然而,当我为使用遵循此模式的函数的基本缓冲区类编写一些热代码时,问题就出现了,因此我希望尽可能避免不必要的虚拟调用。需要注意的是,在我的具体情况下,基类中所有实现的函数都相对较小,只是数量众多。
尽管我有关于可搜索性的观点,但在问完这个问题后不久,我还是设法找到了 以下 StackOverflow 问答。为了汇编程序的简洁性并解决我在问题中指出的问题,我稍微修改了代码。最后,解决方案实际上是我问题中的想法 3 和 4 的结合:
struct base {
virtual int once() = 0;
virtual int shared() = 0;
};
template <typename T>
struct master : base {
virtual int shared() override {
auto ptr = static_cast<T*>(this);
return ptr->once();
}
};
struct derived1 final : public master<derived1> {
int once() final { return 1; }
};
struct derived2 final : public master<derived2> {
int once() final { return 2; }
};
这是编译器资源管理器输出的链接。在链接的代码中,我使用
noinline
指令来说明直接函数调用而不是 vtable 查找,因为 clang 内联了大多数函数调用。
汇编输出显示(至少使用 clang),派生类方法是通过各自的
master<derived1>::shared()
和 master<derived2>::shared()
方法内部的静态分派直接调用的。
这解决了以下痛点: