一、基础知识
- 成员变量最后获取的方式实际是成员变量的地址+成员变量的偏移。
- 成员变量的偏移如何获取. 1) (int)(&((class*)0)->mem) 原理就是成员变量实际位置是对象地址+成员偏移,如果成员偏移为0,则剩下的就是成员的偏移。因此将0转化为类对象,直接获取成员变量地址后强转为int输出。因为没有访问成员变量本身,只是获取了他的偏移,因此不会报错。2)reinterpret_cast(*(void**)(&(class::mem)))
- 打印偏移。printf(“%x”, &class::mem)
二、实践获取偏移
#include#include using namespace std; class A { public: int a = 1; }; class B { public: int b = 2; }; class C :public A, public B { }; void funT(int C::* pCT, C* pC) { printf("%p %pn", pCT, pC); std::cout << pC->*pCT << std::endl; } void fun(C* pC) { int B::* pB = &B::b; printf("%p %pn", pB, pC); funT(pB, pC); } int main() { C pC; fun(&pC); }
测试是否如所想一样。
测试代码
#include#include using namespace std; class A { public: int a = 1; }; class B { public: int b = 2; }; class C :public A, public B { }; void funT(int C::*pCT, C *pC) { printf("%p %pn", pCT, pC); std::cout << pC->*pCT << std::endl; } void fun(C* pC) { int B::* pB = &B::b; int offset = reinterpret_cast (*(void**)&pB); cout << offset << endl; int a = *((char*)pC + ((int)&((B*)0)->b)); int b = *((char*)pC + ((int)&((B*)0)->b) + sizeof(B)); cout << a << " " << b << endl; printf("%p %pn", pB, pC); funT(pB, pC); } int main() { C pC; fun(&pC); }
三、VS 内的 c++内存模型
class A
{
public:
int _a{ 1 };
virtual void funA() {}
};
class B : virtual public A
{
public:
int _b{ 2 };
virtual void funB() {}
};
class C : virtual public A
{
public:
int _c{ 3 };
virtual void funC() {}
};
class D : public B, public C
{
public:
int _d{ 4 };
virtual void funD() {}
};
int main()
{
}
class D size(36):
+---
0 | +--- (base class B)
0 | | {vfptr}
4 | | {vbptr}
8 | | _b
| +---
12 | +--- (base class C)
12 | | {vfptr}
16 | | {vbptr}
20 | | _c
| +---
24 | _d
+---
+--- (virtual base A)
28 | {vfptr}
32 | _a
+---
D::$vftable@B@:
| &D_meta
| 0
0 | &B::funB
1 | &D::funD
D::$vftable@C@:
| -12
0 | &C::funC
D::$vbtable@B@:
0 | -4
1 | 24 (Dd(B+4)A)
D::$vbtable@C@:
0 | -4
1 | 12 (Dd(C+4)A)
D::$vftable@A@:
| -28
0 | &A::funA



