关于c ++:虚函数上final的奇怪行为

Odd behaviour of final on a virtual function

final关键字添加到虚拟函数声明中时,我遇到了一个奇怪的情况,它的定义在一个单独的.cpp文件中。请考虑以下示例:

国际标准化组织

1
2
3
4
5
6
7
8
class IClass //COM-like base interface
{
protected:
    virtual ~IClass(){} //derived classes override this

public:
    virtual void release() final;
};

dllmain.cpp(共享库)

1
2
3
4
5
6
7
8
9
#include"IClass.hpp"
...

void IClass::release()
{
    delete this;
}

...

main.cpp(独立可执行文件)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//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进行了一些挖掘,发现了标记为final get"disvirtualized"的虚拟函数,这是一个优化步骤,旨在通过使用静态调度加快虚拟调用,并可能嵌入它们。

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

这种"脱离现实"行为也出现在Clang上,但不太可能发生在MSVC上。++

部分相关建议

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

  • 抽象基类需要纯虚拟析构函数
  • 在类之外提供析构函数的默认定义(空范围)
  • 像往常一样,在所有派生类上实现析构函数
  • 如果您还处理共享库:

  • 从库中导出一对malloc/free函数
  • 重写库头文件中的非数组new/delete运算符及其各自的std::nothrow版本
  • 调用上面的malloc/free,不使用overriden操作符
  • 由于接口实现将驻留在库中,因此为您认为客户机可构造的每个接口导出一个工厂函数。只需确保异常不会通过客户机和库之间的间隙传播。这样,客户机应用程序就可以在库的CRT分配的对象上使用delete,而不必麻烦。

    < /块引用>