C++语法——详解虚继承

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

目录

一.什么是虚继承

二.虚继承原理

三.虚继承使用注意事项


一.什么是虚继承

所谓虚继承(virtual)就是子类中只有一份间接父类的数据。该技术用于解决多继承中的父类为非虚基类时出现的数据冗余问题,即菱形继承问题。

小编用一张图来表述一下:

如果是下图这种非虚继承,那么D类中就会出现两个 int a,当我们用D实例化对象调用a时,编译会报错,因为发生了混淆。除非指定类域B或C。当然指定A也可以,因为默认会从第一个父类中找。

虚继承,C++语法,子类和间接父类与虚继承关系,虚基表偏移量是什么及原理,虚基表和虚基表指针及内存中存储,虚继承及内存中父类存储形式,C++语法虚继承原理及使用

 此时,D的实例化对象内部结构如下:

虚继承,C++语法,子类和间接父类与虚继承关系,虚基表偏移量是什么及原理,虚基表和虚基表指针及内存中存储,虚继承及内存中父类存储形式,C++语法虚继承原理及使用

而当我们使用虚继承时,结构是下图这样,D中只有一份父类A,当我们调用A中数据时,并不会发生冗余。

虚继承,C++语法,子类和间接父类与虚继承关系,虚基表偏移量是什么及原理,虚基表和虚基表指针及内存中存储,虚继承及内存中父类存储形式,C++语法虚继承原理及使用

 此时,D对象内部结构是这样:

虚继承,C++语法,子类和间接父类与虚继承关系,虚基表偏移量是什么及原理,虚基表和虚基表指针及内存中存储,虚继承及内存中父类存储形式,C++语法虚继承原理及使用

二.虚继承原理

在上图中,父类数据并不存放在虚继承的子类中,那么子类怎么找到父类数据呢?

——在虚继承的类中,会定义一个虚基表指针vbptr指向虚基表

而虚基表中会存在偏移量,这个量就是表的地址到父类数据地址的距离

我们可以通过调试,找到虚基表指针和虚基表:

首先,我们为每一个数据赋值,以便观察:

虚继承,C++语法,子类和间接父类与虚继承关系,虚基表偏移量是什么及原理,虚基表和虚基表指针及内存中存储,虚继承及内存中父类存储形式,C++语法虚继承原理及使用

 之后,调用监视,查看d对象地址和d中a数据地址:

虚继承,C++语法,子类和间接父类与虚继承关系,虚基表偏移量是什么及原理,虚基表和虚基表指针及内存中存储,虚继承及内存中父类存储形式,C++语法虚继承原理及使用

 再通过d的地址查看内存窗口,看d中内存分布:

虚继承,C++语法,子类和间接父类与虚继承关系,虚基表偏移量是什么及原理,虚基表和虚基表指针及内存中存储,虚继承及内存中父类存储形式,C++语法虚继承原理及使用

由此我们可以分析得到对象d及其内部父类的内存布局:

虚继承,C++语法,子类和间接父类与虚继承关系,虚基表偏移量是什么及原理,虚基表和虚基表指针及内存中存储,虚继承及内存中父类存储形式,C++语法虚继承原理及使用

在这个我们可能会有个疑问,那这B和C中两个是什么呢?

虚继承,C++语法,子类和间接父类与虚继承关系,虚基表偏移量是什么及原理,虚基表和虚基表指针及内存中存储,虚继承及内存中父类存储形式,C++语法虚继承原理及使用

 这就是虚基表指针

再通过内存窗口,查看一下虚基表指针指向的地址,根据我们的了解应该就是虚基表,而其中存有偏移量

虚继承,C++语法,子类和间接父类与虚继承关系,虚基表偏移量是什么及原理,虚基表和虚基表指针及内存中存储,虚继承及内存中父类存储形式,C++语法虚继承原理及使用

 而偏移量,就是虚基表指针地址到父类数据地址的距离,这里以b中虚基表为例

虚继承,C++语法,子类和间接父类与虚继承关系,虚基表偏移量是什么及原理,虚基表和虚基表指针及内存中存储,虚继承及内存中父类存储形式,C++语法虚继承原理及使用

到这里我们就能解释一个问题:为什么bptr和cptr能够找到并不位于自己内部的变量a?

虚继承,C++语法,子类和间接父类与虚继承关系,虚基表偏移量是什么及原理,虚基表和虚基表指针及内存中存储,虚继承及内存中父类存储形式,C++语法虚继承原理及使用

因为bptr和cptr都对d进行了切片,当各自寻找变量a时,会从自身的虚基表指针中找到虚基表,通过虚基表的偏移量找到变量a的地址,从而找到了变量a。 

画图解释就是这样:

虚继承,C++语法,子类和间接父类与虚继承关系,虚基表偏移量是什么及原理,虚基表和虚基表指针及内存中存储,虚继承及内存中父类存储形式,C++语法虚继承原理及使用

 文章来源地址https://www.toymoban.com/news/detail-792571.html

三.虚继承使用注意事项

当使用虚继承的时候,需要注意,虚继承只有在多继承时才有用。也就是说如果只有一层继承关系或者是单继承都将不起作用。

因为虚继承是保证子类中只有一个间接父类,说简单一点就是虚继承只能在隔代继承中起作用。

比如下面两种情况即便虚继承也没有意义:

虚继承,C++语法,子类和间接父类与虚继承关系,虚基表偏移量是什么及原理,虚基表和虚基表指针及内存中存储,虚继承及内存中父类存储形式,C++语法虚继承原理及使用

(1)是因为虽然虚继承产生了虚基表和指针,但是class B并没有子类,而虚继承是用以保证子类只有一个间接父类class A。当然话说回来,就算有子类、哪怕多个子类,也都体现不出虚继承,因为虚继承要求同一个子类的多个父类继承自同一个间接父类,而该例只有一个父类class B

(2)是因为虽然class C虚继承了class B,但是class B是class A的非虚继承,那么B中就会有一份A。而class D对A是虚继承,就导致E在实例化时会存放一个对D而言公共的A。这样E中还是存放了两个A。调用变量时还是会混淆。

这样说可能还有些难懂,那换个说法,class B中没有虚基表指针,而D中有虚基表指针,当E从D调用int a时会从虚基表指针找到公共区域的A,而E从B中找只会在B的区域内找到int a。

画图表示E内部结构就是这样:

虚继承,C++语法,子类和间接父类与虚继承关系,虚基表偏移量是什么及原理,虚基表和虚基表指针及内存中存储,虚继承及内存中父类存储形式,C++语法虚继承原理及使用

 正确的继承关系应该是当class A的子类继承时,都是虚继承,这才能保证当有像class E这样的间接子类定义时,class在其中都只会在公共区域有一份。对本例来说即class B是虚继承。

虚继承,C++语法,子类和间接父类与虚继承关系,虚基表偏移量是什么及原理,虚基表和虚基表指针及内存中存储,虚继承及内存中父类存储形式,C++语法虚继承原理及使用

 

 

只有两种编程语言:一种是天天挨骂的,另一种是没人用的——Bjarne Stroustrup(C++之父)


如有错误,敬请斧正

 

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

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

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

相关文章

  • C++(20):多重继承与虚继承

    多重继承 是指从多个直接基类中产生派生类的能力。多重继承的派生类继承了所有父类的属性。 在派生类的派生列表中可以包含多个基类: 每个基类包含一个可选的访问说明符。如果说明符被忽略掉了,则 class 对应的默认访问说明符是 private , struct 对应的是

    2024年02月10日
    浏览(35)
  • C++三大特性—多态 “抽象类与虚函数表”

    抽象类和虚函数表是 C++中实现多态性的重要概念,它们对于学习 C++非常重要。 掌握抽象类和虚函数表的使用方法对于理解 C++的多态性是非常重要的。在 C++中,通过使用抽象类和虚函数表,可以实现基于多态性的各种功能,如继承、多态、模板等。同时,在实际应用中,抽

    2024年02月07日
    浏览(38)
  • C++语法——详解虚继承

    目录 一.什么是虚继承 二.虚继承原理 三.虚继承使用注意事项 所谓虚继承(virtual)就是子类中只有一份间接父类的数据。该技术用于解决多继承中的父类为非虚基类时出现的数据冗余问题,即菱形继承问题。 小编用一张图来表述一下: 如果是下图这种非虚继承 ,那么 D类中

    2024年01月16日
    浏览(38)
  • 【浅尝C++】继承机制=>虚基表/菱形虚继承/继承的概念、定义/基类与派生类对象赋值转换/派生类的默认成员函数等详解

    🏠专栏介绍:浅尝C++专栏是用于记录C++语法基础、STL及内存剖析等。 🎯每日格言:每日努力一点点,技术变化看得见。 我们生活中也有继承的例子,例如:小明继承了孙老师傅做拉面的手艺。继承就是一种延续、复用的方式。C++为了提高代码的可复用性,引入了继承机制,

    2024年04月10日
    浏览(46)
  • Java 强制类型转换原理(父类转子类、子类转父类)

    在Java中,对象的强制转换(也称为类型转换)是将一个对象的引用转换为另一个类的引用,前提是这两个类之间存在继承或实现关系。强制转换可能会导致运行时异常,因为在转换的过程中,如果对象的实际类型与转换的目标类型不兼容,就会抛出ClassCastException异常。 分析

    2024年02月07日
    浏览(36)
  • 链式-父类中返回子类对象

    一晃五年没写博客了,依旧再C#上耕耘,依旧没有啥建树,现在也不知道.net上还有多少人再使用,在这里分享一些自己觉得写的还算优雅的代码。 对于自己写着完的代码,我特别喜欢链式(来源于jQuery的影响吧),大部分时候链式就是将返回值为void类型的对象,返回this指针

    2024年02月05日
    浏览(34)
  • 【C/C++】父类指针指向子类对象 | 隐藏

    创作不易,本篇文章如果帮助到了你,还请点赞 关注支持一下♡𖥦)!! 主页专栏有更多知识,如有疑问欢迎大家指正讨论,共同进步! 🔥c++系列专栏:C/C++零基础到精通 🔥 给大家跳段街舞感谢支持!ጿ ኈ ቼ ዽ ጿ ኈ ቼ ዽ ጿ ኈ ቼ ዽ ጿ ኈ ቼ ዽ ጿ ኈ ቼ c语言内容💖:

    2024年02月11日
    浏览(41)
  • C# 中什么是重写(子类改写父类方法)

    方法重写是指在继承关系中,子类重新实现父类或基类的某个方法。这种方法允许子类根据需要修改或扩展父类或基类的方法功能。在面向对象编程中,方法重写是一种多态的表现形式,它使得子类可以根据不同的需求和场景提供不同的方法实现。 方法重写的基本规则如下:

    2024年02月09日
    浏览(49)
  • Java feign接口调用后返回子类,序列化子类反序列化只得到父类

    需要修改序列化方法 我存的时候放的子类,接收到却是只有父类的数据 feign默认使用jackson进行序列化,需要在父类上加上注解 @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS) 在父类头上增加注解: https://blog.csdn.net/qq_39493105/article/details/126061848

    2024年02月14日
    浏览(43)
  • Java父类强制转换为子类的三种情况(推荐)

    Father f = new Father(); Son s = (Son)f;//出错 ClassCastException Father f = new Son(); Son s = (Son)f;//可以 f只能用父类的方法 s可以用子类的所有方法 Son s = new Son(); Father f = (Father)s;//可以 f只能用父类的方法

    2024年02月08日
    浏览(39)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包