首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

有关C++中多重继承,虚拟基类和对象大小的问题

在C++中,多重继承是指一个类可以从多个基类中继承属性和方法。这种继承方式可能导致一些问题,其中之一是菱形继承问题。为了解决这个问题,C++引入了虚拟基类的概念。虚拟基类是一种特殊的基类,它可以避免在派生类中出现多个副本。

虚拟基类的使用方法是在继承关系中使用关键字virtual。例如:

代码语言:c++
复制
class A { };
class B : virtual public A { };
class C : virtual public A { };
class D : public B, public C { };

在这个例子中,BC都是虚拟基类,它们共享一个A的副本。这样可以避免在D中出现A的多个副本。

对象的大小是由其内存布局决定的。在C++中,对象的大小取决于其成员变量和虚函数表的大小。虚函数表是一个指针,它指向一个虚函数表,其中包含虚函数的地址。如果一个类有虚函数,那么它的对象大小将比没有虚函数的对象大小大一些,因为它需要存储虚函数表指针。

总之,多重继承、虚拟基类和对象大小是C++中的重要概念,它们可以帮助开发人员编写更高效、更可靠的代码。

页面内容是否对你有帮助?
有帮助
没帮助

相关·内容

C# 继承 派生初始化C# 多重继承

C# 继承 继承是面向对象程序设计中最重要概念之一。继承允许我们根据一个来定义另一个,这使得创建和维护应用程序变得更容易。同时也有利于重用代码节省开发时间。...当创建一个时,程序员不需要完全重新编写新数据成员成员函数,只需要设计一个新继承了已有的成员即可。这个已有的被称为,这个新被称为派生。...派生 一个可以派生自多个或接口,这意味着它可以从多个或接口继承数据函数。...C# 创建派生语法如下: class { ... } class : { ... } 假如一个是Shape,一个派生是Rectangle...派生继承成员变量成员方法。

4.5K20

浅谈数字IC验证面向对象编程(抽象继承

在软件工程早期,人们与项目的复杂性增长大型开发团队管理挑战进行了艰巨斗争,面向对象编程(OOP)为解决这些问题带来了革命性解决方案。...面向对象编程使我们可以在软件设计上做同样事情。可以定义一个通用,并使用继承创建该抽象特定实例。...class()定义了对象抽象特征(属性,attributes)行为(方法,methods)。这是一个用于创建一个或多个相同类型对象蓝图(blueprint)。...例如有一个汽车定义了所有汽车对象可以包含东西,然后在该类基础上定义具有某种特殊属性(品牌、颜色引擎等)特殊汽车,例如银色保时捷跑车。 使用继承可以允许具有足够相似接口对象共享代码。...父仅用于实现重用抽象,声明为virtual class,永远不要实例化父对象保存运行时数据并用作构建程序,程序实例化对象并触发对象之间互动。

98810
  • 《挑战30天C++入门极限》图文例解C++多重继承虚拟继承

    图文例解C++多重继承虚拟继承   在过去学习,我们始终接触单个继承,但是在现实生活,一些新事物往往会拥有两个或者两个以上事物属性,为了解决这个问题C++引入了多重继承概念...,C++允许为一个派生指定多个,这样继承结构被称做多重继承。...这是由于多重继承带来继承模糊性带来问题。   ...先看如下图示:   在图中深红色标记出来地方正是主要问题所在,水陆两用汽车继承了来自Car与Boat属性与方法,Car与Boat类同为AmphibianCar,在内存分配上...以上面的代码为例,我们要想让AmphibianCar既获得一个Vehicle拷贝,而且又同时共享用Car与Boat数据成员与成员函数就必须通过C++所提供虚拟继承技术来实现。

    42510

    从零开始学C++之虚继承虚函数对C++对象内存模型造成影响(对象大小

    win32 可选有1, 2, 4, 8, 16 linux 32 可选有1, 2, 4 大小与数据成员有关与成员函数无关 大小与静态数据成员无关 虚继承大小影响 虚函数对大小影响...下面通过实例来展示虚继承虚函数对大小造成影响。...先找到首个vbptr,找到虚BB地址与虚表指针地址差,也即是20,接着pp偏移20个字节指向了dd对象BB部分,然后就访问到了bb_,这是在运行时才做转换。...从输出表成员数据虚函数体可以画出对象内存模型图: ? 上图中vfdd 出现位置跟继承顺序有关,如果DD先继承是B2,那么它将跟在vfb2 下面。...注意:如果没有虚继承,则虚函数表会合并,一个只会存在一个虚函数表一个虚函数表指针(同个对象共享),当然也不会有虚表指针存在。

    1K00

    派生虚函数非虚函数继承效果

    “强制实现”,也就是只要是父指针调用普通函数,那就是父普通函数 而虚函数作用,主要是为了让父指针可以调用子类函数,这种是在运行时才决定调用哪个函数 1、虚函数:   C++虚函数主要作用是...子类可以重写父虚函数实现子类特殊化。 2、纯虚函数:   C++包含纯虚函数,被称为是“抽象”。抽象不能使用new出对象,只有实现了这个纯虚函数子类才能new出对象。   ...C++纯虚函数更像是“只提供申明,没有实现”,是对子类约束,是“接口继承”。   C++纯虚函数也是一种“运行时多态”。...3、普通函数:   普通函数是静态编译,没有运行时多态,只会根据指针或引用“字面值”对象,调用自己普通函数。   普通函数是父为子类提供“强制实现”。   ...因此,在继承关系,子类不应该重写父普通函数,因为函数调用至于对象字面值有关。 参考链接

    8410

    C++继承 ⑦ ( 继承对象模型分析 | 继承构造函数析构函数 )

    一、继承对象模型分析 1、继承代码示例 下面有 3 个 , 分别是 A , B , C ; A ; B 公有继承 A , 并定义了新 成员变量 y ; C ...: A 对象 objA 中有一个成员 int x , 在内存只有一个 int 类型空间 ; B 对象 objB , 除了继承自 A int x 成员 , 还有一个自己 int y...成员 , 在内存是 2 个 int 类型空间 ; C 对象 objC , 除了继承自 B int x int y 成员 , 还有一个自己 int z 成员 , 在内存是 3 个...int 类型空间 ; 3、问题引入 - 派生对象构造函数析构函数调用 上述 继承 过程 , 每一层继承 , 都继承了上一级 父 成员变量 , 同时自己也定义了新成员变量 ; 在 派生对象...---- 1、子类构造函数与析构函数调用顺序 继承构造函数析构函数 : 子类构造 : 子类对象 进行 构造 时 , 需要调用 父 构造函数 对 继承自父 成员变量 进行 初始化 操作

    23040

    C++继承对象模型与继承构造析构顺序

    继承对象模型 问题:从父继承过来成员,哪些属于子类对象?...打开工具窗口后,定位到当前CPP文件盘符 然后输入: cl /d1 reportSingleClassLayout查看名 所属文件名 效果如下图: 结论: 父私有成员也是被子类继承下去了...,只是由编译器给隐藏后访问不到 继承构造析构顺序 子类继承后,当创建子类对象,也会调用父构造函数 问题:父子类构造析构顺序是谁先谁后?...<< endl; } }; void test01() { //继承 先调用父构造函数,再调用子类构造函数,析构顺序与构造相反 Son s; } int main() { test01...(); system("pause"); return 0; } 速记:构造时现有父亲后又儿子,析构顺序相反(白发送黑发) 总结:继承 先调用父构造函数,再调用子类构造函数,析构顺序与构造相反

    58020

    C++封装 ① ( 对象 | 面向对象三大特征 - 封装 继承 多态 | 封装引入 )

    一、对象 1、对象概念 " 面向对象编程 " 是一种 " 编程范式 " , 可以适用于所有的 高级语言 , C++ 也包括在内 ; 面向对象编程 基于 " 对象 " 概念 , 在 对象 可以...: 封装 Encapsulation : 将 数据 操作 封装在 , 可以将 内部 实现细节 隐藏 , 只暴露有限 接口 与外部进行交互 , 从而达到保护 对象 内部状态 不被外部随意修改...; 继承 Inheritance : 创建一个新 子类 , 继承现有 父 属性方法 , 子类可以添加新属性方法以实现更强大功能 , 还可以重写父方法以实现不同行为 ; 通过继承...: 将 数据 操作 封装在 , 可以将 内部 实现细节 隐藏 , 只暴露有限 接口 与外部进行交互 , 从而达到保护 对象 内部状态 不被外部随意修改 ; 将 现实世界 存在...客观事物 封装成 抽象 , 包含了 数据 操作 , 只有 可信 对象 才能访问 隐藏起来信息 ; 大部分类默认只能访问 公开接口 ; C++ , 通过 "

    19110

    C++继承 ⑧ ( 继承 + 组合 模式对象 构造函数 析构函数 调用规则 )

    一、继承 + 组合 模式对象 构造函数析构函数调用规则 1、场景说明 如果一个继承 , 又 在 维护了一个 其它类型 成员变量 , 那么 该类 构造 与 析构 , 就需要涉及到... 本身 构造函数 析构函数 , 父 构造函数 析构函数 , 成员变量 构造函数 析构函数 ; 2、调用规则 在 继承 + 组合 情况下 , 构造函数 与 析构函数 调用规则如下...析构函数 ; 最后 , 调用 父 析构函数 ; 二、完整代码示例分析 ---- 1、代码分析 在下面的代码 , 继承关系 : C 继承了 B class C : public B , B ...继承了 A class B : public A ; 组合关系 : D 是一个普通 , 在 C 维护了一个 D 成员变量 ; class C : public B { public:..." << endl; } ~C() { cout << "C 析构函数调用" << endl; } public: int z; D d; }; 可根据下面的调用规则 , 分析出 C 对象

    18710

    C++真身对象构造(一)

    c语言里面的结构体,现在毕竟在学习c++,所以还是多用class,同时这也就能解释为啥c语言能够写出面向对象思想了): 在使用struct定义时,所有成员默认访问级别为public(也就是说,外部对象可以调用访问里面的东西...,所有成员默认访问级别为private(也就是说外部对象不能调用访问里面的东西了)。  ...在静态存储去创建对象时,对象访问属性初始值为0(就是我们这里gt.i=0,gt.j=0)。...2、其实一般来说对象访问里面的属性都要有一个初始化,在c++里面有一一个构造函数,就可以解决对象访问属性初值问题,就不用管第一条说那样(分栈、堆啥),那我们怎样使用构造函数呢?...首先我们要明白构造函数定义: C++可以定义与名相同特殊成员函数,这个特殊成员函就是构造函数了。 构造函数没有任何返回类型声明。 构造函数在对象定义时自动被调用。

    42920

    虚函数与虚继承寻踪

    继承机制解决了对象复用问题,然而多重继承又会产生成员冲突问题,虚继承在我看来更像是一种“不得已”解决方案。...四、虚拟继承对象模型 虚拟继承是为了解决多重继承下公共多份拷贝问题。...为了消除MyClass子对象多份存在,我们需要让MyClassAMyClassB都虚拟继承于MyClass,然后再让MyClassC多重继承于这两个父。...,除了每个(MyClassAMyClassB)公共(MyClass)虚函数表指针需要记录外,每个虚拟继承了MyClass还需要记录一个虚表vbtable指针vbptr。...尤其是在多重虚拟继承复杂结构。通过这些真实例子,使得我们认清C++内class本质,以此指导我们更好书写我们程序。

    88190

    C++虚拟继承与虚

    1.多重继承带来问题 C++虚拟继承一般发生在多重继承情况下。C++允许一个有多个父,这样就形成多重继承。...多重继承使得派生关系变得更为复杂,其中一个容易出现问题是某个沿着不同路径被派生继承(即形成所谓“菱形继承”),从而导致一个派生对象存在同一个对象多个拷贝。...image.png 多重继承带来同一个对象在派生对象存在多个拷贝问题,考察如下代码。...(2)被虚拟继承,叫做虚。虚实际指的是继承方式,而非一个,是动词,而非名词。 (3)为了实现虚拟继承,派生对象大小会增加4。...因为虚拟继承只是表名某个对象在派生对象只被构造一次,而在本例StudentEmployee对象在EGStudent对象本来就不会被构造多次,所以不将它们申明虚也是完全可以

    90320

    Dart语法详解系列篇(三)-- mixin入门详解一、继承歧义

    如果从A到B继承从A到C继承都标记为virtual(例如,class B:virtual public A),那么c++会特别注意只创建一个对象,并正确使用A成员。...如果虚拟继承虚拟继承是混合,那么只有一个虚拟A,对于每个到A虚拟继承路径,都有一个非虚拟A。C++需要显式地声明要使用特性是从哪个父调用(例如:Worker::Human.Age)。...C++还允许通过虚拟继承机制创建多个单个实例(例如:Worker::HumanMusician::Human将引用相同对象)。...(在Java 8之前,Java不受钻石问题风险影响,因为它不支持多重继承。) Go(可以用于区块链有关) 在编译时防止钻石问题。...Python(可以用于人工智能有关) Python继承顺序影响语义。Python在引入新样式时必须处理这个问题,所有这些都有一个共同祖先对象

    1.8K10

    C++ 虚拟继承

    1.为什么要引入虚拟继承 虚拟继承多重继承特有的概念。虚拟是为解决多重继承而出现。如:D继承B1、B2,而B1、B2都继 承自A,因此在D两次出现A变量函数。...虚拟继承在一般应用很少用到,所以也往往被忽视,这也主要是因为在C++多重继承是不推荐,也并不常用,而一旦离开了多重继承虚拟继承就完全失去了存在必要因为这样只会降低效率占用更多空间。...为什么需要虚继承? 由于C++支持多重继承,那么在这种情况下会出现重复这种情况,也就是说可能出现将一个两次作为可能性。比如像下面的情况 ?...虚拟继承与普通继承不同是,虚拟继承可以防止出现diamond继承时,一个派生同时出现了两个对象。也就是说,为了保证 这一点,在虚拟继承情况下,对象布局是不同于普通继承。...这说明:空所占空间为1,单一继承空类空间也为1,多重继承空类空间还是1.但是虚继承涉及到虚表(虚指针),所以sizeof(C)大小为4 我相信经过上面的分析对比,以后看到这类问题不会再疑惑,会有一种

    2.4K80

    C++继承 ⑥ ( 继承构造函数析构函数 | 类型兼容性原则 | 父指针 指向 子类对象 | 使用 子类对象 为 父对象 进行初始化 )

    一、public 公有继承 - 示例分析 1、类型兼容性原则 类型兼容性原则 : C++ " 类型兼容性原则 “ 又称为 ” 赋值兼容性原则 " ; 子类代替父 : 需要 ( 父 ) 对象...地方 , 都可以使用 " 公有继承 " 派生 ( 子类 ) 对象 替代 , 该 派生 ( 子类 ) 得到了 除 构造函数 析构函数 之外 所有 成员变量 成员方法 ; 功能完整性 :..." 公有继承 " 派生 ( 子类 ) 本质上 具有 ( 父 ) 完整功能 , 使用 可以解决问题 , 使用 公有继承派生 都能解决 ; 特别注意 : " 保护继承 " ..." 私有继承 " 派生 , 是 不具有 完整功能 , 因为 最终继承派生 , 无法在 外部调用 父 公有成员 保护成员 ; 2、类型兼容性原则应用场景 " 类型兼容性原则...子类对象 , 父指针 值为 子类对象 在 堆内存 地址 , 也就是 将 子类对象 地址 赋值给 父类型指针 ; 引用 : 父引用 引用 子类对象 , 将 子类对象 赋值给 父类型引用 ; 二

    28420

    c++对象(上)(定义格式、访问限定符、域、实例化、对象内存大小、this指针)

    前言 c++是一种支持面向对象编程(OOP)语言,而在面向对象编程当中,对象是核心概念,理解对象是学习面向对象编程基石。...二、域 既然学到了,那就不得不提及域了。我们都知道,c++一共有四大域:函数局部域、全局域、命名空间域域。而我们之前在定义成员函数成员变量,就属于域。...三、实例化--对象 1. 实例化概念 与结构体定义创建类似,当我们定义了一个以后,就可以用这个在内存创建出一个对象。所谓对象,指就是根据创建出“变量”。...从代码当中得知,这个包含一个函数fun一个整形变量_x,而整形大小是4个字节,所以说对于对象而言,成员变量内存是包含在其中,而成员函数不在对象当中存储,而是在代码段当中。...总结 今天,我们初入了c++对象大门,学习了概念及定义、实例化出对象,以及this指针概念及作用。

    14910

    c++对象关系_对象只能访问该类私有成员

    以及对象关系以及访问修饰符 一.概念: 二.对象关系: 三.组成: 四.创建: 五.访问修饰符: 一.概念: 是对于某一对象一个统称,对象抽象化,对象实例...二.对象关系: 就是对象抽象化概念,一个就是一个对象集合总称,通俗来讲就是对象需要什么这个就提供什么给对象,加入对象需要什么数据这个就提供什么数据,对象需要什么功能这个就提供什么功能...只有同一个函数可以访问它私有成员。即使是实例也不能访问它私有成员。...访问权限最小意味着针对于对象自己而言最安全; Protected访问修饰符:范围:受保护以及子类可以进行访问,允许子类访问它成员变量成员函数。这样有助于实现继承。...内嵌成员,只有派生可以访问该项; Internal访问修饰符:范围:内部,默认,程序集内部可以访问,允许一个将其成员变量成员函数暴露给当前程序其他函数对象

    1.6K10

    C++|对象模型|对象模型综述

    然而,这种实现方法有很多缺陷: 对象为每个虚背负一个额外指针,而理想上空间负担应该不随虚数目变化。 虚拟继承延伸导致间接层增加,而理想上时间负担应该不随虚拟派生深度变化。...Bjarne Stoustrup采用方式是,在virtual function table存储虚offset。使得虚内存结构依然传统继承一致。...然而单一继承多重继承虚拟继承细节上又有不同。...多重继承下:复杂度问题在于this指针必须在执行期间调整,以正确获取vptr。 例如,如果Derived继承自Base1Base2,temp为已知Derived指针。...虚拟继承下:在虚继承体系单层时,通过上文提及寻址处理,还是可以正确地调整this指针,然而涉及虚继承时,并且都支持virtual functionnonstatic data member

    67010

    C++篇】继承之巅:超越法则束缚,领略面向对象至臻智慧

    第二章:复杂菱形继承虚拟继承 2.1 菱形继承问题 菱形继承C++ 多重继承一种特殊情况。当一个从两个继承,而这两个又有共同时,就会形成一个菱形结构。...传统继承则直接将对象数据存储在派生对象。 传统继承内存布局:派生对象包含每个对象数据。 虚拟继承内存布局:派生对象通过虚表定位到唯一实例。...多重继承与菱形继承多重继承允许一个从多个继承,但也引入了复杂性,特别是菱形继承问题虚拟继承通过 virtual 关键字,可以解决菱形继承数据冗余二义性问题。...虚表与偏移量:虚拟继承通过虚表(VBTable)指针(VBPTR),在运行时动态计算虚位置,从而保证了多重继承唯一性。...写在最后 通过本篇文章学习,我们深入探讨了 C++ 继承进阶知识,包括多重继承虚拟继承使用内存管理,以及它们在实际项目中应用。

    13310

    浅析C++内存布局

    C++在有无继承、有无虚函数、有无多重继承或者虚继承时,其内存布局是不一样。本文将分别阐述各种case。 无继承 1.1....BC内存布局如2.2。接下来看D内存布局: 如上图,D依次存放B subobjectC subobject。其中BC均存放一份class A subobject。...菱形继承不仅浪费存储空间,而且造成了数据访问二义性。虚拟继承可以很好地解决这个问题。 同样以3.2.继承关系为例,不过这次我们BC对A继承都加上了关键字virtual。...而且,从布局上看,class B部分要放在前面,虚A部分放在后面。在class BA成分相对内存起始处偏移offset等于class B大小(8字节)。C内存布局B类似。...总结 可以看到,C++在有无继承、有无虚函数、有无多重继承或者虚继承时,其内存布局大不一样,多重继承或者菱形继承下,内存布局甚至很复杂。大致理清之后,可以对C++内存布局有个清晰认识。

    53510
    领券