菱形继承

来源:互联网 发布:锐捷网络拓扑图素材 编辑:程序博客网 时间:2024/03/29 22:58

什么是继承
继承是面向对象的一种复用手段,通过继承创建一个类,继承是类之间的关系建模,共享共有的东西,是现各自不同的东西。
继承有三种方式:公有继承 保护继承 私有继承
三种继承方式下派生类成员访问基类成员的访问关系
这里写图片描述
注意:不可见,并不是说对象不存在。
如果一个成员定义为私有成员,只有在类内部可以访问,如果一个对象不想被基类对象直接访问,但在派生类中可以被访问,就将其定义为保护成员,可见,保护是因为继承才出现的。
public继承是一个接口继承,每一个父类成员对子类也可以使用,因为每一个子类也是一个父类
public/proteceed继承是一个实现继承,基类的部分成员并未成为子类的一部分,一般情况下都用public继承
!!!使用class的默认继承方式是private,使用struct的默认继承方式时public
继承与转换
子类对象可以直接赋值给父类对象
父类对象不能直接赋值给子类对象(通过强制转换可以实现)
父类对象的指针或引用可以指向子类对象
子类对象的指针不能指向父类对象(通过强制转换可以实现)
继承体系中的作用域
隐藏/重定义:如果父类和子类中有同名成员名(成员+成员函数),子类将屏蔽父类成员直接访问
合成构造函数:子类只初始化自己的成员,父类部分调用父类的成员函数进行初始化
单继承&多重继承
单继承:一个子类只有一个直接父类
多重继承:一个子类有两个或两个以上直接父类
菱形继承:两个子类继承同一个父类,同时又有子类同时继承这两个子类(使用菱形继承时务必使用虚继承)
这里写图片描述
那么菱形继承会有什么问题呢,让我们来看一段代码

class A{public:    void fun1()    {        cout << "fun1()" << endl;    }public:    int _a;};class B :public A{public:    void fun2()    {        cout << "fun2" << endl;    }public:    int _b;};class C:public A{public:    void fun3()    {       cout << "fun3" << endl;    }public:    int _c;};class D :public B, public C{public:    void fun4()    {        cout << "fun4()" << endl;    }public:    int _d;};int main(){    D d;    d._a = 5;//这里编译器会报错,a所指的对象不明确    d._b = 2;    d._c = 3;    d._d = 4;    system("pause");    return 0;

我们可以看出d中保存了两个a对象,编译器不知道d调用的究竟是哪一个a对象这样的话就存数据的二义性问题,并且会造成数据冗余问题。那么我们该如何解决这个问题呢?其实只需给a对象前加域限定符即可

int main(){    D d;    d.B::_a = 1;    d.C::_a = 5;    d._b = 2;    d._c = 3;    d._d = 4;    system("pause");    return 0;}

这样做虽然解决了问题,但容易造成我们的思维混乱,C++中用虚继承来解决数据冗余和数据的二义性问题。


class A
class B1:public virtual A;
class B2:public virtual A;
class D:public B1,public B2;
         
虚函数:在成员函数前加virtual         
 虚函数重写:-当在子类的定义了一个与父类完全相同的虚函数时,则称子类的这个函数重写(也称覆盖)了父类的这个虚函数       
构成多态的条件:虚函数的重写,父类的指针/引用调虚函数   这里写图片描述    
  采用虚拟继承后,就不在是保存基类的值,而是保存基类成员的地址,最后将其公共放在内存最低端           
   最后放一篇自己看到的一篇不错的博客       
   http://www.cnblogs.com/BeyondAnyTime/archive/2012/06/05/2537451.html

原创粉丝点击