先看下面一段代码:
运行于VS2008上的结果是:
为什么会出现这样的结果?下面来进行分析。
先看看上述程序中类的继承关系:
我们先看类X。X类明明是空的,为什么sizeof(X) = 1呢?
原因是因为事实上X并不是空的,它有一个隐晦的1字节,那是编译器安插进去的一个char。这会是的class X的两个objects得以在内存中配置独一无二的地址。
class Y和Z的结果同样令人不解。
事实上Y和Z的大小受到三个因素的影响:
(1)语言本身所造成的额外负担。当语言支持虚基类(virtual base classes)时,就会造成一些额外负担。在子类中,这个额外负担反映在某种形式的指针身上,或者指向虚基类子对象,或者指向一个相关的表格;表格中存放的不是虚基类子对象的地址,就是其偏移量。
(2)编译器对于特殊情况所做的优化处理。虚基类子对象的1字节大小也出现在Y和Z中。传统上放在子类对象的尾端。
现在的编译器一般会对空虚基类提供特殊支持(比如VS2008)。在这个策略下,一个空虚基类被视为子类对象最开头的一部分,也就是说它并没有花费任何的额外空间。这就节省了前述的1字节。(因为既然有了成员,就不需要原本为了空类而安插的1个char)。
(3)Alignment的限制。就是字节对齐,具体可参考:字节对齐详解。在这里没有增加额外的空间。
因此,Y和Z的大小都是4字节。
下面我们讨论A的大小。
这里需要注意的是:一个虚基类子对象只会在继承类中存在一份实体,不管它在继承体系中出现了多少次!!!
A类大小由以下几点决定:
(1)被共享的X类实体,大小为1字节。
(2)Y的大小,需要减去因为虚基类X而配置的大小。4字节。
(3)A自己的大小:0字节。
(4)A字节对齐作用产生的额外空间。
结果是12字节。
注意:C++标准并不强制规定如“基类子对象的排列次序”或不同存取层级的数据成员的排列次序这种琐碎细节。也不规定虚函数和虚基类的实现细节。
分享到:
相关推荐
第四部分 面向对象编程与泛型编程 第15章 面向对象编程 471 15.1 面向对象编程:概述 472 15.2 定义基类和派生类 473 15.2.1 定义基类 474 15.2.2 protected成员 475 15.2.3 派生类 476 15.2.4 virtual与其他成员...
C++是面向对象的语言,主要特征是“封装、继承和多态”。封装隐藏了实现细节,使得代码模块化;派生类可以继承父类的数据和方法,扩展了已经存在的模块,实现了代码重用;多态则是“一个接口,多种实现”,通过派生...
15.9.1 面向对象的解决方案 563 15.9.2 Query_base类和Query类 567 15.9.3 派生类 568 15.9.4 eval函数 571 小结 575 术语表 575 第16章 模板与泛型编程 577 16.1 定义模板 578 16.1.1 函数模板 ...
15.9.1 面向对象的解决方案 563 15.9.2 Query_base类和Query类 567 15.9.3 派生类 568 15.9.4 eval函数 571 小结 575 术语表 575 第16章 模板与泛型编程 577 16.1 定义模板 578 16.1.1 函数模板 ...
9.1 面向对象编程的基本思想 9.2 类的继承 9.2.1 基类的概念 9.2.2 基类的派生类 9.3 继承机制下的访问控制 9.3.1 派生类中构造函数的操作 9.3.2 声明类的保护成员 9.3.3 继承类成员的访问级别 9.4 派生类中的复制...
9.1 面向对象编程的基本思想 9.2 类的继承 9.2.1 基类的概念 9.2.2 基类的派生类 9.3 继承机制下的访问控制 9.3.1 派生类中构造函数的操作 9.3.2 声明类的保护成员 9.3.3 继承类成员的访问级别 9.4 派生类中的复制...
1.1.3 面向对象程序设计方法 1.1.4 最终解决方案:组件软件 1.1.5 面向对象的组件模型——COM 1.2 COM的发展历程 1.2.1 COM以前的对象技术:DDE、OLE 1、VBX控件 1.2.2 COM首次亮相:OLE2 1.2.3 Microsoft拥抱...
这本经典、畅销的数据结构教材详细介绍了数据抽象的基础知识,强调作为面向对象方法基础原理的规范和实施之间的区别。书中使用的软件工程原则和概念以及UML图便于增强学生的理解。 ◆ 详细介绍了数据抽象,强调规范...
9.1 面向对象编程的基本思想 9.2 类的继承 9.2.1 基类的概念 9.2.2 基类的派生类 9.3 继承机制下的访问控制 9.3.1 派生类中构造函数的操作 9.3.2 声明类的保护成员 9.3.3 继承类成员的访问级别 9.4 派生类中的复制...
内容涉及对象的演化、数据抽象、隐藏实现、初始化与清除、函数重载与缺省参数、输入输出流介绍、常量、内联函数、命名控制、引用和拷贝构造函数、运算符重载、动态对象创建、继承和组合、多态和虚函数、模板和包容器...
8.2 引用参数 8.3 函数的重载 8.4 函数的默认函数 8.5 函数重载与歧义性 第9章 更多的数据类型与运算符 第10章 结构与联合 第11章 类 第12章 类的深入学习 第13章 运算符的重载 第14章 继承 第15章 虚函数与多态 第...
通过写高校水电管理系统,使我们更好的掌握C++语言,同时更好的掌握面向对象的设计思想。提高学生自我分析问题,解决问题的能力。 研究的内容和方法 : 本程序通过写文件,将信息从客户终端写入到文件中并保存。在...
9.1 面向对象编程的基本思想 440 9.2 类的继承 441 9.2.1 基类的概念 442 9.2.2 基类的派生类 442 9.3 继承机制下的访问控制 446 9.3.1 派生类中构造函数的操作 448 9.3.2 声明类的保护成员 452 ...
7.2 数据类型、对象、类和实例 301 7.2.1 类的起源 303 7.2.2 类的操作 303 7.2.3 术语 303 7.3 理解类 304 7.3.1 定义类 304 7.3.2 声明类的对象 305 7.3.3 访问类的数据成员 305 7.3.4 类的成员函数 307 ...
9.1 面向对象编程的基本思想 9.2 类的继承 9.2.1 基类的概念 9.2.2 基类的派生类 9.3 继承机制下的访问控制 9.3.1 派生类中构造函数的操作 9.3.2 声明类的保护成员 9.3.3 继承类成员的访问级别 9.4 派生类中的复制...
9.1 面向对象编程的基本思想 9.2 类的继承 9.2.1 基类的概念 9.2.2 基类的派生类 9.3 继承机制下的访问控制 9.3.1 派生类中构造函数的操作 9.3.2 声明类的保护成员 9.3.3 继承类成员的访问级别 9.4 派生类中的复制...
9.1 面向对象编程的基本思想 9.2 类的继承 9.2.1 基类的概念 9.2.2 基类的派生类 9.3 继承机制下的访问控制 9.3.1 派生类中构造函数的操作 9.3.2 声明类的保护成员 9.3.3 继承类成员的访问级别 9.4 派生类中的复制...