c++ - final 在虚函数上的奇怪行为

标签 c++ final c++14 undefined-reference

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;
}

...

ma​​in.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 将报告一个对'IClass::release()'的 undefined reference
我的目标是让 IClass::release() 不可覆盖,同时将其实现隐藏在游戏引擎的共享库中。
有什么建议吗?

最佳答案

对 GCC 对 final 的使用进行了一些挖掘,结果发现虚函数标记为 final get "devirtualized" ,一个旨在通过使用静态分派(dispatch)并可能内联它们来加速虚拟调用的优化步骤。

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

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


部分相关建议

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

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

  • 如果您还处理共享库:

  • 从库中导出一对 Malloc/Free 函数
  • 在您的库的头文件中覆盖非数组新建/删除运算符及其各自的 std::nothrow 版本
  • 从覆盖的操作符中调用上面的 Malloc/Free

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

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

    关于c++ - final 在虚函数上的奇怪行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30314401/

    相关文章:

    c++ - 通用数据库管理器(包装器)

    java - 导入的 java 类中的公共(public)静态最终变量

    java - 无法引用在不同方法中定义的内部类内的非最终变量

    c++ - 如何在 C++14 中实现读/写锁

    c++ - 完美转发复制的 std::tuple

    c++ - 将二维空间中的项目映射到内存中

    c++ - 我们如何在该类中使用运算符?

    c++ - 理解 GLM-openGL 中的相机翻译

    java - Gson反序列化: set final field

    c++ - 如何通过聚合初始化来初始化自定义数组类?