简单虚继承
原则:虚继承解决了菱形继承中派生类拥有多个间接父类实例的情况
■虚继承的子类,如果本身定义了新的虚函数,则编译器为其生成一个新的虚函数指针(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位直接调用子类重写基类的虚函数异常?