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

Posted area-h-p

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了钻石(菱形)继承和虚基类相关的知识,希望对你有一定的参考价值。

钻石(菱形)继承

技术图片

如图,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;//两次赋值均对一个数据成员操作
}

技术图片

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

运行结果

技术图片

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

以上是关于钻石(菱形)继承和虚基类的主要内容,如果未能解决你的问题,请参考以下文章

C++_继承(菱形继承与虚基表)

C++:虚继承中对象模型分析

理解虚基类多重继承的问题

理解虚基类多重继承的问题

多重继承,虚基类

虚基类初始化问题