final 在虚函数上的奇怪行为
Odd behaviour of final on a virtual function
当 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
的使用进行了一些挖掘,结果发现虚拟函数标记为 final get "devirtualized",这是一个旨在通过使用静态调度和可能的内联来加速虚拟调用的优化步骤他们。
这解释了 linker 错误,因为它试图 link IClass::release()
进入可执行文件但未能在本地找到它。
这种 "devirtualization" 行为也出现在 clang 上,但不太可能发生在 MSVC++ 上
部分相关建议
如果您需要通过指向其抽象 class(或抽象基 class)的指针来释放对象的方法:
抽象基class需要一个纯虚析构函数
在 class(空作用域)外提供析构函数的默认定义
像往常一样对所有派生的 classes 执行析构函数
如果您还处理共享库:
从库中导出一对 Malloc/Free 函数
在您的库的头文件中覆盖非数组 new/delete 运算符及其各自的 std::nothrow
版本
从覆盖的运算符 调用上面的Malloc/Free
由于接口实现将驻留在库中,因此为您认为客户端可构造的每个接口导出一个工厂函数。
只需确保异常不会通过客户端和库之间的间隙传播。
这样,客户端应用程序可以在库的 CRT 分配的对象上使用 delete
,没有任何麻烦。
当 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
的使用进行了一些挖掘,结果发现虚拟函数标记为 final get "devirtualized",这是一个旨在通过使用静态调度和可能的内联来加速虚拟调用的优化步骤他们。
这解释了 linker 错误,因为它试图 link IClass::release()
进入可执行文件但未能在本地找到它。
这种 "devirtualization" 行为也出现在 clang 上,但不太可能发生在 MSVC++ 上
部分相关建议
如果您需要通过指向其抽象 class(或抽象基 class)的指针来释放对象的方法:
抽象基class需要一个纯虚析构函数 在 class(空作用域)外提供析构函数的默认定义 像往常一样对所有派生的 classes 执行析构函数
如果您还处理共享库:
从库中导出一对 Malloc/Free 函数 在您的库的头文件中覆盖非数组 new/delete 运算符及其各自的 std::nothrow
版本从覆盖的运算符 调用上面的Malloc/Free
由于接口实现将驻留在库中,因此为您认为客户端可构造的每个接口导出一个工厂函数。
只需确保异常不会通过客户端和库之间的间隙传播。
这样,客户端应用程序可以在库的 CRT 分配的对象上使用delete
,没有任何麻烦。