cpp菱形继承

06-8 菱形继承

菱形继承的概念:存在着两个派生类(类B和类C)继承同一个基类(类A),同时存在着另外一个类(类D)同时继承这两个派生类。这种继承称之为菱形继承,又称之为钻石继承。

我们可以举个例子,这样可能好理解一点:

  • 有一个父类,叫做动物,这个类下面有两个类,一个类是,另外一个类是。这个很好理解,毕竟两个动物嘛......之后又存在一个类,继承,这个动物是草泥马(羊驼)......

    这样是不是好理解一点了......

菱形继承可能会出现的问题:

  1. D会继承类B和类C的数据,而类B和类C又继承了类A的数据。当类D使用数据的时候,就会产生二义性。
  2. D继承了两份类A的数据,但是我们应该清楚,类A的数据我们只需要继承一份就可以了。

所以我们来看一眼

  1. 菱形继承

    class Animal 
    {
    public:
    int m_Age;
    };
    class Sheep :public Animal
    {
    public:
    };
    class Camel :public Animal 
    {
    public:
    };
    class Alpaca :public Sheep, public Camel 
    {
    public:
    };
  2. 菱形继承产生二义性

    #include 
    using namespace std;
    class Animal 
    {
    public:
    int m_Age;
    };
    class Sheep :public Animal
    {
    public:
    };
    class Camel :public Animal 
    {
    public:
    };
    class Alpaca :public Sheep, public Camel 
    {
    public:
    };
    int main()
    {
    class Alpaca a;
    //a.m_Age = 100;
    return 0;
    }

    在这里,我们实例化了一个类Alpaca的对象a。此时,我们想对a的成员属性m_Age赋值,会出现错误。a.m_Age = 100;会产生报错,报错理由如下:

    "Alpaca::m_Age" 不明确

    这就是多继承导致的,解决方法也很简单,只要添加作用域即可。

    class Animal 
    {
    public:
    int m_Age;
    };
    class Sheep :public Animal
    {
    public:
    };
    class Camel :public Animal 
    {
    public:
    };
    class Alpaca :public Sheep, public Camel 
    {
    public:
    };
    int main()
    {
    class Alpaca a;
    a.Sheep::m_Age = 10;
    a.Camel::m_Age = 20;
    cout << "a.Sheep::m_Age = " << a.Sheep::m_Age << endl;
    cout << "a.Camel::m_Age = " << a.Camel::m_Age << endl;
    return 0;
    }

    运行结果:(环境:Windows11(arm/Apple M VM)/Visual Studio 2022/Debug/arm64)

    a.Sheep::m_Age = 10
    a.Camel::m_Age = 20

    当菱形继承的时候,两个父类拥有相同的数据,需要添加作用域用于区分。

  3. 菱形继承导致了多次继承

    如上面的例子,对象a继承了两次m_Age,但是实际上我们只需要一份。这样不仅会导致对线指向不明确,也会造成资源的浪费。

    我们先看一下修改之前的内存对象模型:

    class Alpaca    size(8):
           +---
    0      | +--- (base class Sheep)
    0      | | +--- (base class Animal)
    0      | | | m_Age
           | | +---
           | +---
    4      | +--- (base class Camel)
    4      | | +--- (base class Animal)
    4      | | | m_Age
           | | +---
           | +---
           +---

    我们尝试解决一下:

    利用虚继承可以解决菱形继承的问题。

    虚继承关键字是:virtual,处理方式是:在继承之前加上关键字virtual,可以将这个继承变为虚继承。

    这时候,被继承的类(也就是原来的基类),被称之为:虚基类。

    class Animal 
    {
    public:
    int m_Age;
    };
    class Sheep :virtual public Animal
    {
    public:
    };
    class Camel :virtual public Animal
    {
    public:
    };
    class Alpaca :public Sheep, public Camel 
    {
    public:
    };

    在这里,我们的类Sheep和类Camel都虚继承自类Animal

    我们这时候来看一眼类Alpaca的内存对象模型:

    class Alpaca    size(12):
           +---
    0      | +--- (base class Sheep)
    0      | | {vbptr}
           | +---
    4      | +--- (base class Camel)
    4      | | {vbptr}
           | +---
           +---
           +--- (virtual base Animal)
    8      | m_Age
           +---

    在这里,类Sheep和类Camel继承的内容变为了:{vbptr},这叫做:虚基类指针。(VirtualBasePointer,简称为vbptr)。虚基类指针指向vbtable,这叫做:虚基类表(VirtualBaseTable,简称为vbtable)。在这个表里面,记录的是数据的偏移量。无论是类Sheep还是类Camel,继承的是一个指针,这个指针指向虚基类表,这个表里记录数据的偏移量。通过这个表,可以找到唯一的数据。

    简单来说,使用虚继承,实际上,只有一份真实的数据。

    这个在后续多态部分会详细学习。

    我们再来试一下:

    #include 
    using namespace std;
    class Animal 
    {
    public:
    int m_Age;
    };
    class Sheep :virtual public Animal
    {
    public:
    };
    class Camel :virtual public Animal
    {
    public:
    };
    class Alpaca :public Sheep, public Camel 
    {
    public:
    };
    int main()
    {
    class Alpaca a;
    a.m_Age = 12;
    cout << "a.Sheep::m_Age = " << a.Sheep::m_Age << endl;
    cout << "a.Camel::m_Age = " << a.Camel::m_Age << endl;
    cout << "a.m_Age = " << a.m_Age << endl;
    return 0;
    }

    运行结果:

    a.Sheep::m_Age = 12
    a.Camel::m_Age = 12
    a.m_Age = 12
  • 总结:
    1. 菱形继承是存在着两个派生类(类B和类C)继承同一个基类(类A),同时存在着另外一个类(类D)同时继承这两个派生类。
    2. 菱形继承会出现二义性。我们解决二义性的方式是添加作用域。
    3. 菱形继承可能会出现多次继承,我们需要使用虚继承(virtual)的方式处理。
    4. 虚继承的原理是:继承一个虚基类指针(vbptr),虚基类指针(vbptr)指向虚继承表(vbtable),虚继承表(vbtable)记录数据偏移量,最后找到数据所在的内存空间地址,访问到真实的数据。
文章「cpp菱形继承」,由本站用户「Admin」发布。文章仅代表Admin观点,不代表本站立场。
页面网页地址「https://xiaozhiyuqwq.top/p/939」。
如您对文章及其附件提出版权主张,或进行引用转载等,请查看我们的【版权声明】
无评论:-)

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇