首页
学习
活动
专区
工具
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.3K20

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

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

39710

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

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

94510

从零开始学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 下面。...注意:如果没有虚继承,则虚函数表会合并,一个只会存在一个虚函数表一个虚函数表指针(同个对象共享),当然也不会有虚表指针存在。

97600

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、子类构造函数与析构函数调用顺序 继承构造函数析构函数 : 子类构造 : 子类对象 进行 构造 时 , 需要调用 父 构造函数 对 继承自父 成员变量 进行 初始化 操作

18640

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

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

56320

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

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

14810

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 对象

15410

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

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

41520

C++虚拟继承与虚

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

85520

虚函数与虚继承寻踪

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

84490

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.6K10

C++ 虚拟继承

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

2.1K80

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

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

20720

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

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

1.6K10

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

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

62710

浅析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++内存布局有个清晰认识。

44510

c++继承面试点25连问

2. c++继承优点缺点 优点:根据第1点,其实继承优点就是实现了代码重用接口重用; 缺点:子类会继承部分行为,父任何改变都可能影响子类行为,也就是说,如果继承下来实现不适合子类问题...什么情况下要使用虚继承多重继承时需要使用虚继承,一般我们在多重继承时使用虚继承来防止二义性问题。...有关构造函数最全面的说明请看这篇文章:最全面的c++构造函数高级使用方法及禁忌 14. structclass区别 区别如下: struct成员默认是公有的,class成员默认是私有的。...多重继承对象内存布局 非虚继承时,按照继承顺序存储,虚继承时,虚内容放在一块内存最后面存储。 详细看之前这篇文章:c++头脑风暴-多态、虚继承多重继承内存布局 21....由成员变量是否有虚函数决定,如果类中有虚函数,那就在所有成员变量基础上加上一个虚函数指针大小,在64位机器,虚函数指针为8个字节,注意计算大小时候要考虑字节对齐问题

88710

C++核心准则​讨论:将析构函数设为公共和虚拟,或受保护虚拟

否则,应该对其进行保护,以便只有派生才能在自己析构函数调用它,这个析构函数也应该是非虚,因为它不需要虚拟地运行。...这个简单指南说明了一个微妙问题,并反映了继承和面向对象设计原则现代用法。...如果Base析构函数是公共虚拟(默认值),则可能会意外地在实际上指向派生对象指针上调用它,在这种情况下,尝试删除行为是不确定。...因此,如果可以调用(即是公共析构函数,则它是虚拟,否则是非虚拟。...B是可以自己实例化具体,因此析构函数必须是公共,才能创建和销毁B对象

1.1K20

C++Java中继承比较

两种语言都使用继承来重用代码/或创建“is-a”关系。以下示例将演示 Java C++ 之间提供继承支持差异。  1) 在Java,所有的都直接或间接地继承自Object。...因此,我们不能改变 Java 成员保护级别,如果某个数据成员在是公共或受保护,那么它在派生仍然是公共或受保护。与 C++ 一样,私有成员在派生不可访问。 ...与 C++ 不同,在 Java ,我们不必记住那些由访问说明符继承说明符组合而成继承规则。  5) 在 Java ,方法默认是虚拟。在 C++ ,我们明确使用虚拟关键字。...有关更多详细信息,请参阅此 G-Fact。 6)  Java对接口使用单独关键字interface,对抽象抽象函数使用abstract关键字。 下面是一个 Java 抽象示例。...+不同,Java不支持多重继承;一个不能继承多个

55510
领券