最近Mayuyu在学习C++,对Mayuyu来说C++还是很容易的,因为人家本来就冰雪聪明啊,哈哈!不开玩笑啦,进入
正题。今天Mayuyu将会带领你们一起来学习虚基类。
那么,听到虚基类这个词,你的第一个反应就是什么是虚基类,为什么C++要引入它。那么现在可爱的Mayuyu将会给
你详细探讨。
用五个字概括引入虚基类的目的:消除二义性。我们先来看一段代码:
#include <iostream> #include <string.h> #include <stdio.h> using namespace std; class A { protected: int x; public: void setterA(int x) { this->x = x; } }; class B:public A { public: void changeB() { x += 10; } }; class C:public A { public: void changeC() { x += 20; } }; class D:public B,public C { public: void show() { cout<<x<<endl; } }; int main() { D *d = new D(); d->setterA(10); d->show(); return 0; }
嗯,从上面的代码中可以看出,类B和类C继承父类A,同时类D又继承类B和类C。我们都知道,一般情况下,一个类
要继承另一个类,那么子类从父类中继承下来的所有数据都是重新拷贝了一份,而不是共享原来父类的所有数据。
那么代码中,类B和类C都拷贝了一份类A的数据,然后呢,类D又来拷贝类B和类C的所有数据。现在在类D中,我们有
一个方法叫做show(),它输出的是x的值。这样问题就来了,x有两份拷贝,调用的是哪一个x,类B的还是类C的?
所以到了这里,上述代码编译就会出错,同样的道理主函数中d->setterA(10),到底是调用的类B的setterA()
方法还是类B的setterA()方法,这个不能确定。这个就是我们所说的二义性。那么我们必须要消除这种二义性才
行啊,怎么消除呢?实际上有两种方法:
(1)在调用时候指明要调用所属类的数据,比如修改为cout<<B::x<<endl和d->B::setter(10)。
(2)让类B和类C拥有同一个拷贝,而不是两个不同的拷贝,这就是我们要讲的虚基类。
也就是说,在上面的代码中,A,B,C,D四个类的关系如下:
而在虚基类中类B和类C共享父类A的所有数据,那么就应该是如下拓扑结构
这样,因为只有一个拷贝,所以直接用A的数据就不会引起二义性了,这就是引入虚基类的好处。
所以,我们总结一下:
当一个类的多个直接基类是从另一个共同基类派生而来的,这些直接基类中从上一级基类继承来的成员就拥有
相同的名称。在派生类的对象中,这些同名成员在内存中同时拥有多个拷贝。如何进行分辨呢?当然引入虚基类是
最好的啦!
虚基类的语法格式如下:
class 派生类名:virtual 继承方式 父类名
{
//...
}
这样所有的派生类继承同一个基类时只有一个拷贝了,就消除了二义性。
现在Mayuyu就可以把原代码修改如下:
#include <iostream> #include <string.h> #include <stdio.h> using namespace std; class A { protected: int x; public: void setterA(int x) { this->x = x; } }; class B:virtual public A { public: void changeB() { x += 10; } }; class C:virtual public A { public: void changeC() { x += 20; } }; class D:public B,public C { public: void show() { cout<<x<<endl; } }; int main() { D *d = new D(); d->setterA(10); d->show(); return 0; }
这样编译顺利通过,哈哈!至此虚基类的核心就差不多讲完了。
至此,Mayuyu感谢你的阅读!!!求评论!
原文:http://blog.csdn.net/achelloworld/article/details/22659519