菱形继承

来源:互联网 发布:蓝博清单计价软件 编辑:程序博客网 时间:2024/04/29 05:52

//菱形继承

菱形继承也是多继承的一种方式。

看一段代码:

class A
{
public:
virtual void func1()
{
cout<<"A::func1"<<endl;
}
virtual void func2()
{
cout<<"A::func2"<<endl;
}
public:
int _a;
};
class B :public A
{
public:
virtual void func1()
{
cout<<"B::func1"<<endl;
}
virtual void func3()
{
cout<<"B::func3"<<endl;
}
public:
int _b;
};
class C :public A
{
public:
virtual void func1()
{
cout<<"C::func1"<<endl;
}
virtual void func4()
{
cout<<"C::func4"<<endl;
}
public:
int _c;
};
class D :public B,public C
{
public:
virtual void func1()
{
cout<<"D::func1"<<endl;
}
virtual void func5()
{
cout<<"D::func5"<<endl;
}
public:
int _d;
};
void Test()
{
D d;
d._a = 10;
}
int main()
{
Test();
return 0;
}

这个时候会形成一个菱形继承:如图所示:


而在这时编译会报出错误:



他说:对_a的访问不正确。

打开调试的监视窗口:


在监视窗口中我们可以看到因为B继承了A,所以在B中有一个_a,而C也继承了A,C中也有一个_a,而D继承了B,C,所以在d中也会有两个_a的出现,所以在你访问_a的时候会被报出对_a的不明确的错误。

所以在菱形继承中会出现二义性和数据冗余。

为了解决菱形继承中的二义性和数据冗余,在继承关系中引入了虚继承。在class B :public A,前面加上virtual关键字 即(class B:virtua public A),

同时在class C :public A,前面加上virtual关键字 即(class C:virtua public A),

代码变为:class A
{
public:
virtual void func1()
{
cout<<"A::func1"<<endl;
}
virtual void func2()
{
cout<<"A::func2"<<endl;
}
public:
int _a;
};
class B :virtual public A
{
public:
virtual void func1()
{
cout<<"B::func1"<<endl;
}
virtual void func3()
{
cout<<"B::func3"<<endl;
}
public:
int _b;
};
class C :virtual public A
{
public:
virtual void func1()
{
cout<<"C::func1"<<endl;
}
virtual void func4()
{
cout<<"C::func4"<<endl;
}
public:
int _c;
};
class D :public B,public C
{
public:
virtual void func1()
{
cout<<"D::func1"<<endl;
}
virtual void func5()
{
cout<<"D::func5"<<endl;
}
public:
int _d;
};
void Test()
{
D d;
d._a = 10;
}
int main()
{
Test();
return 0;
}

这个时候就不会报出错误。


调试打开监视窗口:


这个时候对象d中_a的改变也会改变B中的_a和C中的_a.

也就是说编译器把_a放在了一个地方。

这时打开调试内存窗口:


这个时候会发现_a存在_d的后面。

所以在菱形继承中是先继承的放在前面。

这时我们会发现0x00000002上面还有一个地址,再打开一个内存窗口观察:


我们会发现这个地址存的是虚基表的地址,而虚基表中存的是偏移量(即到_a的偏移量)。

而虚基表的地址上面还有一个地址,这个地址其实是虚表的位置。

而虚表的位置存着虚函数的地址,通过地址可以找到对应的虚函数。

总结:虚继承是通过多开空间来存放虚表和虚基表的地址,而通过虚基表中的偏移量可以找到他们所共有的成员变量。通过虚表来找到对应的虚函数。

原创粉丝点击