您的位置:首页 > 其它

多重继承、钻石继承和虚继承

2016-06-16 22:15 393 查看
1、多重继承:一个子类同时继承自多个基类。例如:

电话     播放器     计算机

        \         |          /

          智能手机

名字冲突:如果在子类的多个基类中,存在同名的标识符,而且子类又没有隐藏该名字,那么任何试图在子类中,或通过子类访问该名字的操作,都将引发歧义,除非通过作用域

限定操作符”::“显式指明所属基类,或者通过using声明构成重载。(前提条件,两个父类中的函数必须是符合重载的条件)

2、钻石继承:派生最终子类的多个中间基类源自一个公共基类

        员工         ------公共基类

        /       \

技术员   经理  -----中间基类

          \     /

    技术主管     -----最终子类

#include<iostream>

using namespace std ;

class A{

protected:

    int m_i ;

} ;

class B:public A{

public:

    void set(int i)

    {

        m_i = i ;

    }

} ;

class C:public A{

public:

    int get(){

        return m_i ;

    }

} ;

class D:public B,public C{} ;

int main()

{

    D d ;

    d.set(100) ;

    cout << "d.get():" << d.get() <<endl ;

    return 0;

}

这是因为在构造D类对象时,在d中的两个父类都有各自的A的存储区域,如下图:



派生多个中间基类(B和C)的公共基类(A)子对象,在继承自多个中间基类的最终子类(D)对象中存在多个实例。在最终子类中,或通过最终子类,访问公共基类中的成员,往往会因为继承路径的不同而导致数据不一致的问题。

为了解决这一问题,我们在继承的时候使用class C:virtual public A(虚继承)

虚继承:通过虚继承,可以保证公共基类子对象在最终子类对象中仅存一份实例,且为多个中间基类子对象所共享,进而避免钻石继承的数据不一致问题。如下图:

延伸两个重点:

    A.终极构造

一般而言,子类的构造函数不能调用其间接基类的构造函数。

但是,一旦这个中间基类被声明为虚基类,它的所有子类都必须显式地调用该间接基类的构造函数,否则系统将试图为它的每个子类对象调用该间接基类的缺省构造函数。


class A {

public:

    A (int data) : m_data (data) {}

    int m_data;

};

class B : public A {

class B : virtual public A {

public:

    B (int data) : A (/*data*/8888) {}

};

class D : public B {

public:

    D (int data) : B (data), A (data) {}

};

int main (void) {

    D d (1234);

    cout << d.m_data << endl;

    return 0;

}
     B.阻断继承————构造无法派生出子类的类

class A

{

    A(int data=0):m_data(data){}

    int m_data ;

public:

    void set(int data)

    {

        m_data=data ;

    }

    int get()const

    {

        return m_data ;

    }

} ;

class B:public A{} ;

int main()

{

    B b ;

    b.set(1234) ;

    cout << b.get() << endl ;

}

这个程序编译通不过,是因为在基类A中的构造函数是私有的,所以在创建对象时,子类无法调用基类的构造函数。

#include <iostream>

using namespace std;

class A {

    A (int data = 0) : m_data (data) {}

public:

    void set (int data) {

        m_data = data;

    }

    int get (void) const {

        return m_data;

    }

private:

    int m_data;

    friend class AA;

};

class AA : virtual public A {

public:

    AA (int data = 0) : A (data) {}

};

class B : public AA {};

int main (void) {

    AA a;

    a.set (1234);

    cout << a.get () << endl;

    B b;

    return 0;

}

在上述函数中,AA类成为了一个不可继承的类。AA类可以创建自己的对象,但是由于AA类是A类的友元类,所以AA类可以通过初始化表的形式去调用A类中的私有构造函数,所以AA类可以像正常类一样去初始化,去做一个A类的子类。但是不能被其他类继承,因为AA类是虚继承与A类的,所以每一个AA类的派生类都会去调用A类的私有构造函数,所以无法正常继承。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: