虚函数上final的奇怪行为

Odd behaviour of final on a virtual function

本文关键字:函数 final      更新时间:2023-10-16

我遇到了一个奇怪的情况,当final关键字被添加到一个虚函数声明中,它的定义在一个单独的。cpp文件中。
考虑下面的例子:

IClass.hpp

class IClass //COM-like base interface
{
protected:
    virtual ~IClass(){} //derived classes override this
public:
    virtual void release() final;
};
dllmain.cpp(共享库)
#include "IClass.hpp"
...
void IClass::release()
{
    delete this;
}
...

main.cpp(独立执行)

//various includes here
...
int main(int argc, char** argv)
{
    /* From "IGameEngine.hpp"
       class IGameEngine : public IClass
       {
       ...
       };
    */
    IGameEngine* engine = factoryGameEngine();
    ...
    engine->release();
    return 0;
}

事实上,GCC 4.9.2将报告一个undefined reference to 'IClass::release()'
我的目标是将IClass::release()作为不可重写的,同时将其实现隐藏在游戏引擎的共享库中。有什么建议吗?

对GCC对final的使用进行了一些挖掘,结果发现虚拟函数标记为最终获得"去虚拟化",这是一个优化步骤,旨在通过使用静态调度加速虚拟调用,并可能内联它们。

这解释了链接器错误,因为它试图将IClass::release()链接到可执行文件中,但无法在本地找到它。

这种"去虚拟化"行为也出现在clang上,但不太可能发生在msvc++上


部分相关建议

<引用类>

如果您需要通过指向其抽象类(或抽象基类)的指针来释放对象:

  • 抽象基类需要一个纯虚析构函数
  • 在类之外提供析构函数的默认定义(空作用域)
  • 在所有派生类上实现析构函数,像往常一样

  • 如果你也在处理共享库:

  • 从库中导出一对Malloc/Free函数
  • 覆盖非数组的new/delete操作符和它们各自在库头文件中的std::nothrow版本
  • 从被覆盖的操作符中调用上述Malloc/Free

  • 由于接口实现将驻留在库中,因此为每个您认为客户端可构造的接口导出一个工厂函数。只要确保异常不会通过客户端和库之间的间隙传播。

    这样,客户机应用程序就可以在库的CRT分配的对象上使用delete,没有麻烦。