菱形继承对象模型
下面用一段菱形继承的代码来探究菱形继承的对象模型
class AA
{
public:
virtual void fun1()
{
cout << "AA::fun1()" << endl;
}
public:
int _a;
};
class BB : public AA
{
public:
virtual void fun1()
{
cout << "BB::fun1()" << endl;
}
public:
int _b;
};
class CC : public AA
{
public:
virtual void fun1()
{
cout << "CC::fun1()" << endl;
}
public:
int _c;
};
class DD :public BB,public CC
{
public:
virtual void fun1()
{
cout << "DD::fun1()" << endl;
}
virtual void fun2()
{
cout << "DD::fun2()" << endl;
}
public:
int _d;
};
void Test1()
{
DD d;
d.BB::_a = 1;
d.CC::_a = 2;
d._b = 3;
d._c = 4;
d._d = 5;
}
打开内存窗口,进行单步调试,结果如下:
对于对象d,重写了fun1(),所以将DD的fun1()放入虚表,再将fun2()放入虚表,图片中另一个虚表指针指向的是CC中的虚函数,CC中的fun1()重写了AA中的fun1(),所以在虚表中放入CC的fun1()。这一这样理解,橙色区域本来应给是AA类,续表中存储的是AA::fun1()的地址,但是BB类中从写了fun1(),所以把AA::fun1()替换为了CC::fun1()。所以,对于一个类中的虚函数,若是重写的父类的,则将虚表中的函数地址替换为自己的虚函数地址,若不是重写的函数,则直接将该函数地址放入虚表中。
菱形虚拟继承对象模型
现在把上面的代码改为虚拟继承,再来看内存窗口中的结果:
下面提供完整的代码调用虚函数
class AA
{
public:
virtual void fun1()
{
cout << "AA::fun1()" << endl;
}
public:
int _a;
};
class BB : virtual public AA
{
public:
virtual void fun1()
{
cout << "BB::fun1()" << endl;
}
public:
int _b;
};
class CC : virtual public AA
{
public:
virtual void fun1()
{
cout << "CC::fun1()" << endl;
}
public:
int _c;
};
class DD :public BB,public CC
{
public:
virtual void fun1()
{
cout << "DD::fun1()" << endl;
}
virtual void fun2()
{
cout << "DD::fun2()" << endl;
}
public:
int _d;
};
typedef void(*FUNC) ();
void PrintfVTable(int *VTable)
{
cout << "虚表地址:" << "0x" << VTable << endl;
for (int i = 0; VTable[i] != 0; ++i)
{
cout << "虚函数地址:0x" << VTable[i] << " ";
FUNC f = (FUNC)VTable[i];
f();
}
cout << endl;
}
void Test1()
{
DD d;
d.BB::_a = 1;
d.CC::_a = 2;
d._b = 3;
d._c = 4;
d._d = 5;
int* VTable = (int *)(*(int *)&d);
PrintfVTable(VTable);
VTable = (int *)(*((int*)&d + 6));
PrintfVTable(VTable);
}