C++ 内存分析(3)

简单虚继承
原则:虚继承解决了菱形继承中派生类拥有多个间接父类实例的情况
    ■虚继承的子类,如果本身定义了新的虚函数,则编译器为其生成一个新的虚函数指针(vptr)以及一张虚函数表。该vptr位于对象内存最前面(对比非虚继承:直接扩展父类虚函数表);(先子后父 )   /* "最前面" ,有待大神指教*/
    ■虚继承的子类也单独保留了父类的vptr与虚函数表;
    ■虚继承的子类有虚基类表指针(vbptr)。

.h

//简单虚继承
class FSimpleVirtualDerive : virtual public FBase
{
public:
	FSimpleVirtualDerive() {}
	virtual ~FSimpleVirtualDerive() {}
public:
	//重写 基类虚函数
	virtual void BaseVirtualFun1() override { std::cout << "FSimpleVirtualDerive::BaseVirtualFun1()\n"; }
	//新增虚函数
	virtual void VirtualFun3() { std::cout << "FSimpleVirtualDerive::VirtualFun3()\n"; }
public:
	char m_cSimpleVirtualDeriveMemeber;
};

.cpp

void SimpleVirtualDerive_Test()
{
	std::cout << std::endl << std::endl << "------------------------------------SimpleVirtualDerive_Test-------------------------Start" << std::endl;
	FSimpleVirtualDerive SimpleVirtualDerive;
	/* x86:
			00EA328E  push        1  
			00EA3290  lea         ecx,[SimpleVirtualDerive]  
			00EA3293  call        FSimpleVirtualDerive::FSimpleVirtualDerive (0EA149Ch)  
			00EA3298  mov         dword ptr [ebp-4],0  
	   x64:
			00007FF725A08909  mov         edx,1  
			00007FF725A0890E  lea         rcx,[SimpleVirtualDerive]  
			00007FF725A08912  call        FSimpleVirtualDerive::FSimpleVirtualDerive (07FF725A01046h)  
			00007FF725A08917  nop  
				SimpleVirtualDerive.m_cBaseMemeber = 8;
			00007FF7F6608918  mov         rax,qword ptr [rbp+10h]
			00007FF7F660891C  movsxd      rax,dword ptr [rax+4]
			00007FF7F6608920  mov         byte ptr [rbp+rax+18h],8
				SimpleVirtualDerive.m_cSimpleVirtualDeriveMemeber = 9;
			00007FF7F6608925  mov         byte ptr [rbp+18h],9
	*/
	SimpleVirtualDerive.m_cBaseMemeber = 8;
	SimpleVirtualDerive.m_cSimpleVirtualDeriveMemeber = 10;

	//结构大小
	STREXE_D(sizeof(SimpleVirtualDerive));//x64-26;	x86-14;
	long *lV_ptr = (long *)&SimpleVirtualDerive;
	long long *llV_ptr = (long long*)&SimpleVirtualDerive;
	//首地址
	std::cout << "VPtr地址l:" << std::hex << *lV_ptr << std::endl;
	std::cout << "VPtr地址ll:" << std::hex << *llV_ptr << std::endl;
	std::cout << "&SimpleVirtualDerive:" << std::hex << &SimpleVirtualDerive << std::endl;
	STREXE_HEX((long long*)&(SimpleVirtualDerive.m_cBaseMemeber));
	STREXE_HEX((long long*)&(SimpleVirtualDerive.m_cSimpleVirtualDeriveMemeber));

	//SimpleVirtualDerive Function
	pFun* F1 = nullptr;
	//Base Function
	pFun* BaseF1 = nullptr;
	int nPointerSize = 0;
#ifdef _WIN64
	//默认构造内的一个指针,占4个字节
	nPointerSize = sizeof(long long);
	F1 = (pFun*)((char*)(*llV_ptr)+ nPointerSize);
	//虚基类表指针
	long long * pSimpleVirtualDeriveMem = (long long *)((char*)(&SimpleVirtualDerive) + nPointerSize + nPointerSize);
	long long * pVbptr = (long long *)((char*)(pSimpleVirtualDeriveMem) + sizeof(char));
	//long long* lBaseV_ptr = (long long*)((char*)(pVbptr) + nPointerSize);// (long long*)((((char*)pSimpleVirtualDeriveMem) + nPointerSize));
	//BaseF1 = (pFun*)(*lBaseV_ptr);
	long long* BaseMemeber = (long long*)((char*)(&SimpleVirtualDerive) + sizeof(SimpleVirtualDerive)- sizeof(char));
	long long* lBaseV_ptr = (long long*)((char*)(&SimpleVirtualDerive) + sizeof(SimpleVirtualDerive) - sizeof(char)- nPointerSize);
	//long long * pVbptr = (long long*)((char*)(&SimpleVirtualDerive) + sizeof(SimpleVirtualDerive) - sizeof(char) - nPointerSize - nPointerSize);
	BaseF1 = (pFun*)(*lBaseV_ptr);//140699019104880		0x7FF7 0B0D D270
#else 
#ifdef _WIN32	
	//默认构造内的一个指针
	nPointerSize = sizeof(long);
	F1 = (pFun*)(*lV_ptr+ nPointerSize);
	//虚基类表指针
	long * pSimpleVirtualDeriveMem = (long *)((char*)(&SimpleVirtualDerive) + nPointerSize + nPointerSize);
	long * pVbptr = (long *)(((char*)pSimpleVirtualDeriveMem )+ sizeof(char));
	long* lBaseV_ptr = (long*)((((char*)pVbptr) + nPointerSize));
	BaseF1 = (pFun*)(*lBaseV_ptr);
	long* BaseMemeber = (long*)((char*)lBaseV_ptr + nPointerSize);
#endif
#endif
	//SimpleVirtualDerive函数调用
	std::cout << "SimpleVirtualDerive函数调用:--------------------------------" << std::endl;
	(*F1)();
	//虚基类表---SimpleVirtualDerive与Vbptr的偏移值
	std::cout << "虚基类表---SimpleVirtualDerive与Vbptr的偏移值:--------------------------------" << std::endl;
	STREXE_HEX(pVbptr);
	STREXE_D((int)(*pVbptr));
	for (int nIdx = 1; nIdx < 12; ++nIdx)
	{
		STREXE_HEX((char*)pVbptr + nIdx);
		STREXE_D(nIdx);
		STREXE_D((int)(*((char*)pVbptr + nIdx)));
	}
	STREXE_HEX((char*)pVbptr + 1);
	STREXE_D((int)(*((char*)pVbptr + 1)));
	//虚基类表---FBase与Vbptr的偏移值
	std::cout << "虚基类表---FBase与Vbptr的偏移值:--------------------------------" << std::endl;
	STREXE_D((int)(*((char*)pVbptr+ sizeof(int))));
	//成员m_cSimpleVirtualDeriveMemeber
	std::cout << "成员m_cSimpleVirtualDeriveMemeber:--------------------------------" << std::endl;
	STREXE_D(&(SimpleVirtualDerive.m_cSimpleVirtualDeriveMemeber));
	STREXE_D(SimpleVirtualDerive.m_cSimpleVirtualDeriveMemeber);
	STREXE_D((char)(*pSimpleVirtualDeriveMem));
	STREXE_D((char)(*(long long*)((char*)&SimpleVirtualDerive + 16)));
	//Base2函数调用
	std::cout << "Base函数调用:--------------------------------" << std::endl;
//#if !_WIN64
	//(*BaseF1)();//x64异常:0x00007FF6D1622B38 处(位于 VirtualMechanismMemoryTest.exe 中)引发的异常: 0xC0000005: 读取位置 0x00000000FFFFFFFB 时发生访问冲突。
//#endif	
	(*(BaseF1 + 1))();

	typedef void (FBase::*BaseVirtualFun_Test)();
	//FSimpleVirtualDerive::BaseVirtualFun1()
	BaseVirtualFun_Test pBVF1 = &FBase::BaseVirtualFun1;
	(SimpleVirtualDerive.*pBVF1)();

	long long* llBasevptr = (long long*)(*(long long*)((char*)&SimpleVirtualDerive + 21));
	BaseVirtualFun_Test BaseF = *(BaseVirtualFun_Test *)(llBasevptr);
	//FSimpleVirtualDerive::BaseVirtualFun1()
	(SimpleVirtualDerive.*BaseF)();
	BaseVirtualFun_Test BVF2 = *(BaseVirtualFun_Test *)(llBasevptr + 1);
	//FBase::BaseVirtualFun2()
	(SimpleVirtualDerive.*BVF2)();

	//成员m_cBase2Memeber
	std::cout << "成员m_cBaseMemeber:--------------------------------" << std::endl;
	STREXE_D(&(SimpleVirtualDerive.m_cBaseMemeber));
	STREXE_D(SimpleVirtualDerive.m_cBaseMemeber);
	STREXE_D((char)(*BaseMemeber));
	STREXE_D((char)(*(long long*)((char*)&SimpleVirtualDerive + 29)));

	std::cout << "------------------------------------SimpleVirtualDerive_Test-------------------------End" << std::endl;
}

疑问:

1.64位直接调用子类重写基类的虚函数异常?

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值