Calculate offset of base class at compile time(编译时计算基类的偏移量)
问题描述
我想知道是否可以在编译时计算基类偏移量。当然,在运行时很容易做到这一点,因为可以利用static_cast的功能,而偏移量只是指向派生类的指针的基指针之间的差异。
我第一次尝试在编译时获取它,结果如下所示:
struct InterfaceRoot {};
struct IInterface1 : InterfaceRoot {
virtual void MethodI1() = 0;
};
struct IInterface2 : InterfaceRoot {
virtual void MethodI2() = 0;
};
class CClass : public IInterface1, public IInterface2 {
virtual void MethodI1() override { /* do something */ }
virtual void MethodI2() override { /* do something */ }
};
int main() {
CClass instance;
constexpr int offsetI1 = 0; //first base class has no offset
constexpr int offsetI2 = sizeof(IInterface1);
//check pointer values against static_cast
IInterface1* pI1 = reinterpret_cast<IInterface1*>(reinterpret_cast<char*>(&instance) + offsetI1);
IInterface2* pI2 = reinterpret_cast<IInterface2*>(reinterpret_cast<char*>(&instance) + offsetI2);
IInterface1* pI1_static_cast = static_cast<IInterface1*>(&instance);
IInterface2* pI2_static_cast = static_cast<IInterface2*>(&instance);
return 0;
}
这里,pI1和pI1_static_cast与预期相同。然而,pI2和pI2_static_cast并不相等!?
我可以通过向InterfaceRoot添加一个虚函数或将其全部省略来修复此问题。发生这种情况的原因是什么?
如果我这样设置继承树,它将使用前面提到的方法:
struct InterfaceRoot {
virtual ~InterfaceRoot() {}
};
struct IInterface1 : InterfaceRoot {
virtual void MethodI1() = 0;
};
struct IInterface2 : InterfaceRoot {
virtual void MethodI2() = 0;
};
class CClass : public IInterface1, public IInterface2 {
virtual void MethodI1() override { /* do something */ }
virtual void MethodI2() override { /* do something */ }
};
有人知道这是为什么吗?顺便说一句,我正在使用Visual Studio 2017。有没有其他方法可以在编译时实现我的目标,或者我最好在运行时计算ofset并具有较小的运行时开销?
编辑:
工作的运行时实现可能如下所示:
template<typename Derived, typename Base>
inline int CalcBaseOffset() {
const static int s_off = (reinterpret_cast<char*>(static_cast<Base*>(reinterpret_cast<Derived*>(0x10000000))) - reinterpret_cast<char*>(0x10000000));
return s_off;
};
int main() {
//...
int offsetI1_RT = CalcBaseOffset<CClass, IInterface1>();
int offsetI2_RT = CalcBaseOffset<CClass, IInterface2>();
// add offsets to pointer like in the code sample above
}
此方法可产生准确的结果,但以小的运行时开销为代价(如果无法在编译时计算偏移量以消除此开销,则运行时开销是可接受的)。
推荐答案
编译器可能会在基类IInterface1和IInterface2之间的CClas中引入填充。
基本X:sizeof(CClas)>;=sizeof(IInterface1)+sizeof(IInterface2)
然后,以下语句可能会返回错误的地址:
IInterface2*Pi2= Reinterpret_cast<;IInterface2*>;(reinterpret_cast<;char*>;(&;instance)+ 偏移量I2
X请注意,如果基类没有virtual成员函数并且由于Empty Base Optimization而为空(即没有数据成员),则这可能不成立。
这篇关于编译时计算基类的偏移量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:编译时计算基类的偏移量
基础教程推荐
- 如何在 C++ 中初始化静态常量成员? 2022-01-01
- C++结构和函数声明。为什么它不能编译? 2022-11-07
- 在 C++ 中计算滚动/移动平均值 2021-01-01
- 如何将 std::pair 的排序 std::list 转换为 std::map 2022-01-01
- 静态库、静态链接动态库和动态链接动态库的 .lib 文件里面是什么? 2021-01-01
- 如何检查GTK+3.0中的小部件类型? 2022-11-30
- 这个宏可以转换成函数吗? 2022-01-01
- 如何通过C程序打开命令提示符Cmd 2022-12-09
- 我有静态或动态 boost 库吗? 2021-01-01
- 常量变量在标题中不起作用 2021-01-01
