C++ 虚函数上final的奇性

C++ 虚函数上final的奇性,c++,final,c++14,undefined-reference,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(共享库) main.cpp(

我遇到了一个奇怪的情况,将
final
关键字添加到虚拟函数声明中,其定义位于单独的.cpp文件中。
考虑下面的例子:

IClass.hpp

class IClass //COM-like base interface
{
protected:
    virtual ~IClass(){} //derived classes override this

public:
    virtual void release() final;
};
dllmain.cpp(共享库)

main.cpp(独立可执行)

实际上,GCC4.9.2将报告对“IClass::release()”的
未定义引用。

我的目标是使
IClass::release()
不可重写,同时将其实现隐藏在游戏引擎的共享库中。

有什么建议吗?

对GCC使用的
final
做了一些挖掘,发现了标记为final-get的虚拟函数,这是一个优化步骤,旨在通过使用静态分派和可能的内联来加速虚拟调用

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

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


部分相关建议

如果您需要通过指向其抽象类(或抽象基类)的指针释放对象的方法:
  • 抽象基类需要一个纯虚拟析构函数
  • 在类之外提供析构函数的默认定义(空范围)
  • 像往常一样,在所有派生类上实现析构函数

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

  • 从库中导出一对Malloc/Free函数
  • 覆盖库头文件上的非数组new/delete运算符及其相应的
    std::nothrow
    版本
  • 从重写的运算符调用上述Malloc/Free

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

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


    除非是纯函数,否则通常使用odr。我相信在这种情况下,链接器可以发布错误。我无法在GCC4.9.2中重现该问题。请添加如何构建程序(编译器选项等)是否从dll导出函数@0x49 I误以为它们的odr使用的是实现定义的。@dyp:dll是使用此函数构建的。主二进制文件使用相同的编译器标志,但以下链接器标志:
    -static libgcc-static libstdc++-mwindows
    @Yakk[basic.def.odr]/p5:“如果虚拟成员函数不是纯函数,则使用odr。”我认为是否存在链接器错误取决于实现。
    #include "IClass.hpp"
    ...
    
    void IClass::release()
    {
        delete this;
    }
    
    ...
    
    //various includes here
    ...
    
    int main(int argc, char** argv)
    {
        /* From "IGameEngine.hpp"
           class IGameEngine : public IClass
           {
           ...
           };
        */
        IGameEngine* engine = factoryGameEngine();
        ...
        engine->release();
        return 0;
    }