菱形继承
c++支持多继承,因此可能出现菱形继承。菱形继承是指,派生类B和派生类C同时继承基类A,派生类D又同时继承B和C,代码如下:
#include "iostream"
using namespace std;
class baseClass
{
private:
int i;
char c;
public:
virtual void virt_fun1(){ cout << "baseClass virt_fun1" << endl; }
virtual void virt_fun2(){ cout << "baseClass virt_fun2" << endl; }
void comm_fun1(){ cout << "baseClass comm_fun1" << endl; }
void comm_fun2(){ cout << "baseClass comm_fun2" << endl; }
baseClass() { cout << "tihs is baseClass" << endl; }
~baseClass() { cout << "~~ baseClass" << endl; }
};
class inheritClass_1 : public baseClass
{
private:
char c;
public:
virtual void virt_fun1(){ cout << "inheritClass virt_fun1" << endl; }
virtual void virt_fun3(){ cout << "inheritClass virt_fun2" << endl; }
inheritClass_1() { cout << "tihs is inheritClass_1" << endl; }
~inheritClass_1() { cout << "~~ inheritClass_1" << endl; }
};
class inheritClass_2 : public baseClass
{
private:
char c;
public:
virtual void virt_fun2(){ cout << "inheritClass virt_fun1" << endl; }
virtual void virt_fun3(){ cout << "inheritClass virt_fun2" << endl; }
inheritClass_2() { cout << "tihs is inheritClass_2" << endl; }
~inheritClass_2() { cout << "~~ inheritClass_2" << endl; }
};
class inheritClass_3 : public inheritClass_1, public inheritClass_2
{
private:
char c;
public:
virtual void virt_fun1(){ cout << "inheritClass virt_fun1" << endl; }
virtual void virt_fun2(){ cout << "inheritClass virt_fun2" << endl; }
virtual void virt_fun3(){ cout << "inheritClass virt_fun2" << endl; }
inheritClass_3() { cout << "tihs is inheritClass_3" << endl; }
~inheritClass_3() { cout << "~~ inheritClass_3" << endl; }
};
int _tmain(int argc, _TCHAR* argv[])
{
inheritClass_3 a;
return 0;
}
运行程序,输出如下:
从运行结果来看,基类被构造和析构两次,这显然是不合理的(如果派生类inheritClass_3 的对象要访问baseClass类的成员,则由于baseClass的成员存在两份,导致二义性,程序出错)。
inheritClass_3共占用36字节(36字节容易理解)内存,内存分布如下:
从内存分布中可以看出
1:inheritClass_3继承inheritClass_1和inheritClass_2时,这两个类又继承baseClass,所以才导致inheritClass_3中保存了两份baseClass的成员。
2:inheritClass_1成员在内存中的地址最低,而后是inheritClass_2的成员,最后才是inheritClass_3的成员。
虚继承 -1
如果派生类B和派生类C同时继承基类A,派生类D同时虚继承B和C,能否解决该问题呢?代码如下:
#include "iostream"
using namespace std;
class baseClass
{
private:
int i;
char c;
public:
virtual void virt_fun1(){ cout << "baseClass virt_fun1" << endl; }
virtual void virt_fun2(){ cout << "baseClass virt_fun2" << endl; }
void comm_fun1(){ cout << "baseClass comm_fun1" << endl; }
void comm_fun2(){ cout << "baseClass comm_fun2" << endl; }
baseClass() { cout << "tihs is baseClass" << endl; }
~baseClass() { cout << "~~ baseClass" << endl; }
};
class inheritClass_1 : public baseClass
{
private:
char c;
public:
virtual void virt_fun1(){ cout << "inheritClass virt_fun1" << endl; }
virtual void virt_fun3(){ cout << "inheritClass virt_fun2" << endl; }
inheritClass_1() { cout << "tihs is inheritClass_1" << endl; }
~inheritClass_1() { cout << "~~ inheritClass_1" << endl; }
};
class inheritClass_2 : public baseClass
{
private:
char c;
public:
virtual void virt_fun2(){ cout << "inheritClass virt_fun1" << endl; }
virtual void virt_fun3(){ cout << "inheritClass virt_fun2" << endl; }
inheritClass_2() { cout << "tihs is inheritClass_2" << endl; }
~inheritClass_2() { cout << "~~ inheritClass_2" << endl; }
};
class inheritClass_3 : public virtual inheritClass_1, public virtual inheritClass_2
{
private:
char c;
public:
virtual void virt_fun1(){ cout << "inheritClass virt_fun1" << endl; }
virtual void virt_fun2(){ cout << "inheritClass virt_fun2" << endl; }
virtual void virt_fun3(){ cout << "inheritClass virt_fun2" << endl; }
inheritClass_3() { cout << "tihs is inheritClass_3" << endl; }
~inheritClass_3() { cout << "~~ inheritClass_3" << endl; }
};
int _tmain(int argc, _TCHAR* argv[])
{
inheritClass_3 a;
return 0;
}
问题并没有解决,程序执行结果如下:
inheritClass_3占用48字节内存,内存分布如下:
由于inheritClass_3虚继承inheritClass_1和inheritClass_2,所以inheritClass_3增加了一个vbptr(4字节),同时由于派生类和基类存在同名虚函数,故多出2×4=8字节的(vtordisp)内存。
下面简单介绍一下vtordisp,参看MSDN“虚继承中派生类重写了基类的虚函数,并且在构造函数或者析构函数中使用指向基类的指针调用了该函数,编译器会为虚基类添加vtordisp域”,所以vtordisp产生条件:
1:派生类重写了虚基类的虚函数。
2:派生类定义了构造函数或者析构函数。
从内存分布中可以看出inheritClass_3虽然同时虚继承inheritClass_1和inheritClass_2,但是inheritClass_1和inheritClass_2在继承baseClass时不是虚继承,从而inheritClass_1和inheritClass_2都包含了一份baseClass,导致inheritClass_3中依旧有两份baseClass。
虚继承-2
由于虚继承-1并不能解决菱形继承的问题,并且从内存分布看inheritClass_1和inheritClass_2各自保留了一份baseClass,那如果inheritClass_1和inheritClass_2都是虚继承baseClass,然后被inheritClass_3继承(非虚继承),是不是就能解决问题呢?代码如下:
#include "iostream"
using namespace std;
class baseClass
{
private:
int i;
char c;
public:
virtual void virt_fun1(){ cout << "baseClass virt_fun1" << endl; }
virtual void virt_fun2(){ cout << "baseClass virt_fun2" << endl; }
void comm_fun1(){ cout << "baseClass comm_fun1" << endl; }
void comm_fun2(){ cout << "baseClass comm_fun2" << endl; }
baseClass() { cout << "tihs is baseClass" << endl; }
~baseClass() { cout << "~~ baseClass" << endl; }
};
class inheritClass_1 : public virtual baseClass
{
private:
char c;
public:
virtual void virt_fun1(){ cout << "inheritClass virt_fun1" << endl; }
virtual void virt_fun3(){ cout << "inheritClass virt_fun2" << endl; }
inheritClass_1() { cout << "tihs is inheritClass_1" << endl; }
~inheritClass_1() { cout << "~~ inheritClass_1" << endl; }
};
class inheritClass_2 : public virtual baseClass
{
private:
char c;
public:
virtual void virt_fun2(){ cout << "inheritClass virt_fun1" << endl; }
virtual void virt_fun3(){ cout << "inheritClass virt_fun2" << endl; }
inheritClass_2() { cout << "tihs is inheritClass_2" << endl; }
~inheritClass_2() { cout << "~~ inheritClass_2" << endl; }
};
class inheritClass_3 : public inheritClass_1, public inheritClass_2
{
private:
char c;
public:
virtual void virt_fun1(){ cout << "inheritClass virt_fun1" << endl; }
virtual void virt_fun2(){ cout << "inheritClass virt_fun2" << endl; }
virtual void virt_fun3(){ cout << "inheritClass virt_fun2" << endl; }
inheritClass_3() { cout << "tihs is inheritClass_3" << endl; }
~inheritClass_3() { cout << "~~ inheritClass_3" << endl; }
};
int _tmain(int argc, _TCHAR* argv[])
{
inheritClass_3 a;
return 0;
}
程序运行结果:
从运行结果看,生成inheritClass_3时,只有一份baseClass,问题解决。
inheritClass_3占用44字节内存,内存分布如下:
inheritClass_1(inheritClass_2)占用28字节,内存分布如下:
从内存分布可以看出:
1:虚继承时基类在内存中的地址比派生类的地址大(基类在派生类下面)
2:普通继承(非虚继承)基类的地址比派生类的地址小(基类在派生类上面)
3:菱形继承时,如果被继承的类都是虚继承与基类,那么基类会被合并。从而消除二义性