C++学习之路(九):从菱形继承引入的对象模型
一、单继承
class A {int a;};
class B : public A {int b;};
普通的单继承关系,类的大小是由其虚表指针和非静态成员函数大小决定。故上述sizeof(A)的大小为4。
类B公有继承A,对象模型如下:
类A的非静态成员(4字节)
类B的非静态成员(4字节)
故类B的大小为8字节。
二、多继承
class A {int a;};
class B {int b;};
class C : public A, public B {int c;};
普通的多继承关系,这里和上述单继承类似。直接给出类C的对象模型如下:
类A的非静态成员(4字节)
类B的非静态成员(4字节)
类C的非静态成员(4字节)
故类C的大小为12字节。
三、含有虚函数的普通继承
(1)含有虚函数的类对象模型
C++中引入了虚函数,即多态的概念。如果一个类中存在虚函数,则该类对象在被实例化时,其首地址开始的4个字节存放着虚函数表指针(vptr),vptr指向了一个虚表(理解为结构体数组),数组中的每一个位置存放着虚函数的实际地址。(ps:一个类的大小与其非成员变量有关,所以如果一个仅包含虚函数的类,其大小只有一个虚表指针,即4字节)
class A
{
virtual void test(void);
int a;
};
故上述类A的大小为,一个vptr加上一个成员变量,为8字节。
(2)含有虚函数的普通单继承
class A
{
virtual void test(void);
int a;
}; class B : public A
{
int b;
};
类B直接继承类A,由于类A中存在虚函数,所以类B对象中同样也会有vptr虚表指针,并指向一个虚表,用于重写test函数。类B的对象模型如下:
类B的vptr(4字节) -----> 指向了一个虚表
类A的非静态成员(4字节)
类B的非静态成员(4字节)
故类B的大小为12字节。(先虚表,然后是基类的成员,最后是子类的成员)
(3)含有虚函数的多继承
含有虚函数的多继承
class A
{
virtual void test_a(void){}
int a;
}; class B
{
virtual void test_b(void){}
int b;
}; class C : public A, public B {int c;};
类C的对象模型如下:
类A的vptr
A::a
类B的vptr
B::b
C::c
四、含有虚函数的类对象虚继承
class A
{
virtual void test(void);
int a;
}; class B : public virtual A
{
void test(void);
virtual void test1(void);
int b;
};
直接给出类B的对象模型如下:
类B的vptr(4字节) -----> 指向虚表,新增的虚函数放在自己的虚表
类B的非静态成员(4字节)
类A的vptr(4字节) ------> 指向虚表,重写的虚函数放在这个虚表。保存B::test()
类A的非静态成员(4字节)
故类B的大小为16字节。
五、菱形继承
所谓菱形继承,是一种较为特殊的多继承关系,融合了多继承与虚继承。如图:

结合代码如下:
class X {};
class Y : public virtual X {};
class Z : public virtual X {};
class A : public Y, public Z {};
如果通过sizeof输出上述四个类的大小,结果为:1,4,4,8。
(1)、空类的大小
C++定义一个类如果是一个空类,会被编译器默认插入一个char(1个字节),从而使得该类的两个对象在内存中可以有独一无二的地址。所以上述sizeof(X)结果为1
(2)、虚继承类的大小
在虚继承的子类中,子类除了vptr,还会增加一种形式的指针。这个指针或者指向虚基类子对象,或者指向一个相关的表格,表格中存放的不是虚基类子对象的地址,就是其偏移量,这个指针被称为bptr。(在同时存在vptr和bptr的时候,某些编译器会将其优化,合并为一个指针)
故上述Y和Z,自身包含指针bptr(占四个字节),继承X的非静态成员变量(占0个字节),故sizeof(Y)和sizeof(Z)结果都为4。
(3)、类A的大小
A是直接从Y和Z多继承而来,由于X是一个虚基类(子类都虚继承),所以在A中仅仅会存在一个X类的副本。整个A的对象结构为:
类Y的bptr(4字节)
类Y的非静态成员(0字节)
类Z的bptr(4字节)
类Z的非静态成员(0字节)
类A的非静态成员(0字节)
类X的非静态成员(0字节)
故sizeof(X)结果为8。这里从上往下分别是Y和Z的顺序,是由类A的继承顺序决定的。
参考:https://www.cnblogs.com/fanzhidongyzby/archive/2013/01/14/2859064.html
C++学习之路(九):从菱形继承引入的对象模型的更多相关文章
- 【jq】c#零基础学习之路(3)继承和虚方法
c#只能继承一个基类和多个接口(0+) 父类:Human: class Human { public virtual Move() { Console.WriteLine("Human的虚方 ...
- Android开发学习之路-自定义ListView(继承BaseAdapter)
大三学生一个,喜欢编程,喜欢谷歌,喜欢Android,所以选择的方向自然是Android应用开发,开博第一篇,希望以后会有更多的进步. 最近在做一个记账App的时候,需要一个Activity来显示每个 ...
- zigbee学习之路(九):串口(发送)
一.前言 今天,我们来学习和实验串口模块方面的,串口通信是我们常用的通信手段,通过串口交互,我们可以很容易的和pc机进行数据的交换和发送,所以我们今天就来学习一下.这个实验所进行的功能是一开始CC25 ...
- 嵌入式Linux驱动学习之路(九)Linux系统调用、驱动程序框架
应用程序通过open read write close 等函数来操作计算机硬件.类似是一个接口. 当应用程序调用这些接口程序时,计算机是如何进入内核的呢?这是经过了系统调用. 实际上当调用接口函数 ...
- Object-c学习之路九(字典(NSDictionary&NSMutableDictionary))
字典的练习和使用(遍历,搜索...)(Student和Book类文件可以查看上篇博客这次不上传了.) // // main.m // NSDictionary // // Created by Wil ...
- IOS7学习之路九(ios7自定义UIAlertView)
IOS7的UIAlertView 不支持自定义,无法添加subview . 不过可以用第三方库git上的下载链接 https://github.com/wimagguc/ios-custom-a ...
- IOS学习之路九(配置restful webservice 框架restkit)
RestKit 是一个开源的 objective-c 框架,容许在 iOS 和 Mac OS X 的 Objective-C 中与 RESTful Web 办事进行交互,包含简单的 HTTP requ ...
- Java学习之路(九):Map集合
Map集合概述和特点 Map是属于java.util的一个接口Map<k,v> k:映射所维护的键的类型 v:映射值的类型 Map是将键映射到值的对象.一个映射不能包含重复的键:每个键最多 ...
- Qt 学习之路 2(10):对象模型
Home / Qt 学习之路 2 / Qt 学习之路 2(10):对象模型 Qt 学习之路 2(10):对象模型 豆子 2012年9月2日 Qt 学习之路 2 45条评论 标准 C++ 对象模 ...
随机推荐
- Css实现拖动效果
效果如下,可以拖动滑块,数字显示的是离左侧距离:
- C++解析(6):函数参数的扩展
0.目录 1.函数参数的默认值 2.函数默认参数的规则 3.函数占位参数 4.小结 1.函数参数的默认值 C++可以在函数声明时为参数提供一个默认值 当函数调用时没有提供参数的值,则使用默认值 参数的 ...
- 【Codeforces 98E】 Help Shrek and Donkey 游戏策略神题
from http://www.cnblogs.com/MashiroSky/p/6576398.html A君有n张牌,B君有m张牌,桌上还有一张反扣着的牌,每张牌都不一样. 每个回合可以做两件事中 ...
- 洛谷P4609 [FJOI2016]建筑师 【第一类斯特林数】
题目链接 洛谷P4609 题解 感性理解一下: 一神带\(n\)坑 所以我们只需将除了\(n\)外的\(n - 1\)个元素分成\(A + B - 2\)个集合,每个集合选出最大的在一端,剩余进行排列 ...
- [ZJOI2007]棋盘制作 【最大同色矩形】
题目描述 国际象棋是世界上最古老的博弈游戏之一,和中国的围棋.象棋以及日本的将棋同享盛名.据说国际象棋起源于易经的思想,棋盘是一个8*8大小的黑白相间的方阵,对应八八六十四卦,黑白对应阴阳. 而我们的 ...
- 解题:POI 2009 Lyz
题面 板板讲的霍尔定理 霍尔定理:一张二分图有完全匹配的充要条件是对于任$i$个左部点都有至少$i$个右部点与它们相邻.放在这个题里就是说显然最容易使得鞋不够的情况是一段连续的人,那就维护一下最大子段 ...
- Ciesz się Polską
SZKOpułPoi at BZOJPA at BZOJONTAK at BZOJ Chinese Solution of Poi
- 【单调队列】【P3957】 跳房子
传送门 Description 跳房子,也叫跳飞机,是一种世界性的儿童游戏,也是中国民间传统的体育游戏之一. 跳房子的游戏规则如下: 在地面上确定一个起点,然后在起点右侧画 $n$ 个格子,这些格子都 ...
- 《JavaScript高级程序设计(第三版)》-3
相等操作符 相等和不相等 在转换不同的数据类型时,相等和不想等操作符遵循下面基本规则: 如果有一个操作符数是布尔值,则在比较相等性之前先将其转换为数值——false转换为0,而true转换为1: 如果 ...
- python学习笔记(六) 函数式编程
一 函数对象 函数同样可以作为对象复制给一个变量,如下: f = abs; print(f(-10)) f = 'abs'; print(f) def add(a,b,f): return f(a) ...