C++:面向对象大坑:菱形继承

这篇具有很好参考价值的文章主要介绍了C++:面向对象大坑:菱形继承。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1.单继承

1.概念

单继承:一个子类只有一个直接父类时称这个继承关系为单继承。

图示:
C++:面向对象大坑:菱形继承,c++,开发语言,程序人生,交友,c语言,visualstudio,面试

2.多继承

2.1概念

多继承:一个子类有两个或以上直接父类时称这个继承关系为多继承。

图示:
C++:面向对象大坑:菱形继承,c++,开发语言,程序人生,交友,c语言,visualstudio,面试

2.2菱形继承

1.概念

菱形继承:菱形继承是多继承的一种特殊情况。即:一个类是另外几个类的子类,而这几个子类又是另外一个类的父类。

基本模型:

C++:面向对象大坑:菱形继承,c++,开发语言,程序人生,交友,c语言,visualstudio,面试

2.问题

但是呢,菱形继承却有一些问题:它会造成数据的冗余以及数据的二义性。比如下面,在Assistant的对象中Person成员会有两份。

C++:面向对象大坑:菱形继承,c++,开发语言,程序人生,交友,c语言,visualstudio,面试

3.样例理解

注:以下在VS2022 X64环境下验证。

class A
{
public:
	int _a;
};
class B : public A
{
public:
	int _b;
};
class C : public A
{
public:
	int _c;
};
class D : public B, public C
{
public:
	int _d;
};
int main()
{
	D d;
	d.B::_a = 1;
	d.C::_a = 2;
	d._b = 3;
	d._c = 4;
	d._d = 5;
	return 0;
}
二义性

如果我们直接访问d中的_a,编译器不知道要访问继承B的 _a还是继承C的 _a,会有歧义。

C++:面向对象大坑:菱形继承,c++,开发语言,程序人生,交友,c语言,visualstudio,面试
C++:面向对象大坑:菱形继承,c++,开发语言,程序人生,交友,c语言,visualstudio,面试

数据冗余

首先观察调试窗口:我们可以看到创建的d变量的地址。

C++:面向对象大坑:菱形继承,c++,开发语言,程序人生,交友,c语言,visualstudio,面试
然后通过内存窗口,我们可以看到d中存储了2个_a,相同的部分就会重复存储。
C++:面向对象大坑:菱形继承,c++,开发语言,程序人生,交友,c语言,visualstudio,面试

对于内存模型抽象化

C++:面向对象大坑:菱形继承,c++,开发语言,程序人生,交友,c语言,visualstudio,面试

2.3菱形虚拟继承(解决菱形继承的问题)

1.概念

菱形虚拟继承就是在菱形继承的腰部继承时(即父类第一次有多个子类时)加上关键字virtual即可。

2.样例理解

其他部分不变,我们对于上述代码进行菱形虚拟继承,并且加上一句直接访问的代码(d._a = 100),再次进行测试。

class A
{
public:
	int _a;
};
class B : virtual public A
{
public:
	int _b;
};
class C : virtual public A
{
public:
	int _c;
};
class D : public B, public C
{
public:
	int _d;
};
int main()
{
	D d;
	d.B::_a = 1;
	d.C::_a = 2;
    d._a = 100; //新增的一句代码
	d._b = 3;
	d._c = 4;
	d._d = 5;
	return 0;
}

首先观察调试窗口:我们可以看到创建的d变量的地址。
C++:面向对象大坑:菱形继承,c++,开发语言,程序人生,交友,c语言,visualstudio,面试

此时再让代码执行d.B::_a = 1这句,通过内存窗口可以看到其变化,但是和菱形继承的变化位置不同。
C++:面向对象大坑:菱形继承,c++,开发语言,程序人生,交友,c语言,visualstudio,面试
再让代码执行d.C::_a = 2这句,通过内存窗口可以看到其是直接在原来的位置处改变的,只有一份 _a。
C++:面向对象大坑:菱形继承,c++,开发语言,程序人生,交友,c语言,visualstudio,面试
再让代码执行d._a = 100这句,内存窗口变化如下:
C++:面向对象大坑:菱形继承,c++,开发语言,程序人生,交友,c语言,visualstudio,面试
再执行d._b = 3这条语句。
C++:面向对象大坑:菱形继承,c++,开发语言,程序人生,交友,c语言,visualstudio,面试
再执行d._c = 4这条语句。
C++:面向对象大坑:菱形继承,c++,开发语言,程序人生,交友,c语言,visualstudio,面试

再执行d._d = 5这条语句。
C++:面向对象大坑:菱形继承,c++,开发语言,程序人生,交友,c语言,visualstudio,面试
有个疑问,此处圈住的部分是什么呢?它看起来像一个地址(X64环境下),那么其是存储什么的呢?

解释一下,其确实为两个指针,指向的一张表。这两个指针叫虚基表指针,这两个表叫虚基表。虚基表中存的偏移量。通过偏移量可以找到下面的A。
C++:面向对象大坑:菱形继承,c++,开发语言,程序人生,交友,c语言,visualstudio,面试

通过内存窗口可以观察出:继承的B中存储了十六进制下的28,即十进制下的40。对比下图,和偏移量相等。
C++:面向对象大坑:菱形继承,c++,开发语言,程序人生,交友,c语言,visualstudio,面试
C++:面向对象大坑:菱形继承,c++,开发语言,程序人生,交友,c语言,visualstudio,面试
C++:面向对象大坑:菱形继承,c++,开发语言,程序人生,交友,c语言,visualstudio,面试

对于内存模型抽象化

C++:面向对象大坑:菱形继承,c++,开发语言,程序人生,交友,c语言,visualstudio,面试

2.4总结

1.通过虚拟继承,D类对象中只有一个A类的_a,从而解决了数据冗余和二义性。
2.菱形虚拟继承的对象模型:
每个继承对象中存储一个虚基表,虚基类(即上例中的A)放在最下面,成为公共部分。
C++:面向对象大坑:菱形继承,c++,开发语言,程序人生,交友,c语言,visualstudio,面试
3.存储的地址的作用
其为虚基表指针,指向虚基表,虚基表中存储偏移量,可以找到下面存储的A。从而方便切片的场景。
4.菱形虚拟继承也会改变中间类的结构,让它们的结构和D的结构类似。
这样是为了防止以下的场景:

D d;
B b;
B& ref = d;
ref = b;

如果不存储成类似的结构,那么找到B类存储的_a就比较困难。

3.问题总结

1.C++有多继承,为什么?为什么Java没有?

这个得从C++历史发展来看,在C++发展史中,在完善面向对象的过程中,祖师爷考虑到了现实生活中确实有一部分东西可以继承多个类,比如西红柿既是水果,又是蔬菜,因此C++有了多继承。而Java在这方面通过C++的痛苦因此做出了 改变,只允许单继承。

2.多继承的问题是什么?

多继承本身没有问题,但是有多继承就会有菱形继承,而菱形继承就有许多问题。

3.菱形继承的问题是什么,如何解决?

数据冗余以及二义性。通过菱形虚拟继承解决。

4.底层角度如何解决菱形继承的问题(数据冗余和二义性)?

菱形虚拟继承在底层改变了数据的存储结构,将虚基类存储在了最下面,作为公共部分,让多继承而来的父类的数据共享,共用一份,而在继承的那部分中则存储了虚表指针,指向虚基表,从而得到其中存储的偏移量,进而可以实现切片时数据的完整性。文章来源地址https://www.toymoban.com/news/detail-860047.html

到了这里,关于C++:面向对象大坑:菱形继承的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • C++ 面向对象(2)——继承

    面向对象程序设计中最重要的一个概念是继承。继承允许我们依据另一个类来定义一个类,这使得创建和维护一个应用程序变得更容易。这样做,也达到了重用代码功能和提高执行效率的效果。 当创建一个类时,您不需要重新编写新的数据成员和成员函数,只需指定新建的类

    2024年02月10日
    浏览(44)
  • C++ 面向对象三大特性——继承

    ✅1主页:我的代码爱吃辣 📃2知识讲解:C++ 继承 ☂️3开发环境:Visual Studio 2022 💬4前言:面向对象三大特性的,封装,继承,多态,今天我们研究研究 C++的继承 。 目录 一.继承的概念及定义 1.继承的概念  2.继承的定义 二. 继承关系和访问限定符  三.基类和派生类对象赋

    2024年02月12日
    浏览(66)
  • go语言(十一)----面向对象继承

    一、面向对象继承 写一个父类 子类继承 父类 子类的新方法 定义子类 两种方法: 第一种: 第二种: 子类继承父类的使用

    2024年01月22日
    浏览(39)
  • 【面向对象语言三大特性之 “继承”】

    目录 1.继承的概念及定义 1.1继承的概念 1.2 继承定义 1.2.1定义格式  1.2.2继承关系和访问限定符  1.2.3继承基类成员访问方式的变化 2.基类和派生类对象赋值转换 3.继承中的作用域 4.派生类的默认成员函数 5.继承与友元 6. 继承与静态成员 7.复杂的菱形继承及菱形虚拟继承 8.继

    2023年04月08日
    浏览(43)
  • 【C++面向对象】--- 继承 的奥秘(下篇)

    个人主页:平行线也会相交💪 欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 平行线也会相交 原创 收录于专栏【C++之路】💌 本专栏旨在记录C++的学习路线,望对大家有所帮助🙇‍ 希望我们一起努力、成长,共同进步。🍓 接下来对C++继承体系中的 作用域 展开分析。 在C

    2024年02月12日
    浏览(41)
  • 【C++面向对象】--- 继承 的奥秘(上篇)

    个人主页:平行线也会相交💪 欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 平行线也会相交 原创 收录于专栏【C++之路】💌 本专栏旨在记录C++的学习路线,望对大家有所帮助🙇‍ 希望我们一起努力、成长,共同进步。🍓 C++支持面向对象 ,其中面向对象有三大特性,即

    2024年02月13日
    浏览(40)
  • 第八站:C++面向对象(继承和派生)

     派生:由父类派生出子类 继承:子类继承父类(继承不会继承 析构函数和构造函数 : 父类的所有成员函数,以及数据成员,都会被子类继承! ) \\\"子类派生出的类\\\"会指向\\\"父类被继承的类\\\", 父类就是基类 实例1: 先创建一个父类,有私有成员数据(name,和age),成员函数,描述信息,有参的

    2024年01月19日
    浏览(42)
  • c++面向对象之封装、继承、和多态

    把客观事物封装成类,而且可以把自己的数据和方法设置为只能让可信的类或者对象操作,对不可信的信息进行隐藏(利用public,private,protected,friend)实现 has-a :描述一个类由多个部件类构成,一个类的成员属性是另一个已经定义好的类。 use-a:一个类使用另一个类,通过类之间

    2024年02月02日
    浏览(48)
  • 面向对象的三大特性之继承(C++)

    概念   继承机制是面向对象编编程使代码可以复用的最重要的手段,它允许程序员在保持原有类特性的基础上进行扩展,增加功能,这样产生新的类,称为派生类。继承呈现了面向对象程序设计的层次结构,体现了由简单到复杂的认知过程。继承是类设计层次的复用。 定

    2024年02月06日
    浏览(49)
  • C++ 面向对象核心(继承、权限、多态、抽象类)

    继承(Inheritance)是面向对象编程中的一个重要概念,它允许一个类(称为派生类或子类)从另一个类(称为基类或父类)继承属性和方法。继承是实现类之间的关系,通过继承,子类可以重用父类的代码,并且可以在此基础上添加新的功能或修改已有的功能。 在C++中,继承

    2024年02月08日
    浏览(45)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包