钻石(菱形)继承和虚基类

钻石(菱形)继承

如图,B,C继承了A,D继承了B,C

在这种情况下,如果D类的对象通过B、C两个不同的作用域调用A的数据成员,将会产生两个

不同的A的数据成员值

如下(Grandfather对应A,a是其公有数据成员,Father1,Father2对应B、C,son对应D的对象,)

可以看到有两个不一样的a存在,说明在赋值过程中Father1,Father2分别调用Grandfather产生两个a

从其运行结果也可以看出来

如果son对象仅想产生一个数据成员a,则必须对Grandfather进行虚继承

//Test1.h
#include<iostream>
using namespace std;
class Grandfather
{
public:
    int a;
    Grandfather(int _a):a(_a) 
    {
        cout<<"Grandfather was built. "<<endl;
    }
    ~Grandfather(){cout<<"Grandfather was free. "<<endl;}
};
class Father1 : public virtual Grandfather
{
public:
    int n;
    Father1(int _a) : n(_a),Grandfather(_a)
    {
        cout<<"Father1 was built. "<<endl;
    }
    ~Father1(){cout<<"Father1 was free. "<<endl;}
};
class Father2 : virtual public Grandfather //virtual写在public前后都可以
{
public:
    int n;
    Father2(int _a) : n(_a),Grandfather(_a)
    {
        cout<<"Father2 was built. "<<endl;
    }
    ~Father2(){cout<<"Father2 was free. "<<endl;}
};
class Son : public Father1, public Father2
{
public:
    Son(int _a):Father1(_a),Father2(_a),Grandfather(_a)
    {
        cout<<"Son was built. "<<endl;
    }
    ~Son(){cout<<"Son was free. "<<endl;}
};

虚继承就是在继承符(public、protected、private)前或后加上virtual关键字,被虚继承的类也叫虚基类

在派生类对象的创建中,

首先是虚基类的构造函数并按他们声明顺序构造。

第二批是非虚基类的构造函数按他们声明的顺序调用

第三批是成员对象的构造函数

最后是派生类自己的构造函数。

#include"Test1.h"
void main()
{
    Son son(10);
    son.Father1::n = 1;
    son.Father2::n = 2;//由于在Father1,Father2内均存在公有数据n,在对其赋值时需要加上作用域
    son.Father1::a = 5;
    son.Father2::a = 6;//两次赋值均对一个数据成员操作
}

可以看到两个数据成员的地址相同。

运行结果

析构顺序和构造顺序相反。

猜你喜欢

转载自www.cnblogs.com/area-h-p/p/10350517.html