父类包括成员函数、静态函数、静态方法,子类包括成员函数、静态函数、静态方法的情况与一个类时完全一致,这里就不做分析了。子类单独包含虚函数时继承无关,也不做分析了。

  一、父类子类都为空

#include <cstdio>

class A
{ }; class B: public A
{ }; int main(int argc, char** argv)
{
printf("%d\n", sizeof(B));
}

  windows输出:

1

  和一个空类时情况一致。

  二、父类包含成员变量、子类包含成员变量或子类父类都包含成员变量

#include <cstdio>

class A
{
public:
int a;
}; class B: public A
{ }; class AA
{ }; class BB: public AA
{
public:
int b;
}; class AAA
{
public:
int a;
}; class BBB: public AAA
{
public:
int b;
}; int main(int argc, char** argv)
{
printf("%d\n", sizeof(B));
printf("%d\n", sizeof(BB));
printf("%d\n", sizeof(BBB));
}

  windows输出:

4
4
8

  内存为成员变量,包括父类的。

  三、父类包含虚函数,子类未实现该函数

#include <cstdio>

class A
{
public:
int a;
virtual void vfun(){};
}; class B: public A
{ }; int main(int argc, char** argv)
{
printf("%d\n", sizeof(B)); B b;
b.a = 0xaaaaaaaa;
B* pb = &b;
printf("%08x\n", pb);
}

  windows输出:

8
003ffe40

  查看对象b的内存:

003FFE40 4C
003FFE41 57
003FFE42 22 00
003FFE44 AA
003FFE45 AA
003FFE46 AA
003FFE47 AA

  查看虚表0x0022574c:

B::`vftable':
0022574C 22 11 
0022574E 22 00 
00225750 00 00 
00225752 00 00

  查看虚表指向的地址:

A::vfun:
00221122 E9 19 04 00 00 jmp A::vfun (221540h)

7: virtual void vfun(){};
00221540 55 push ebp
00221541 8B EC mov ebp,esp
00221543 81 EC CC 00 00 00 sub esp,0CCh

  可知b.vfun()执行的是a的虚函数。

  四、父类包含虚函数、子类实现该函数

#include <cstdio>

class A
{
public:
int a;
virtual void vfun(){};
}; class B: public A
{
public:
void vfun(){};
}; int main(int argc, char** argv)
{
printf("%d\n", sizeof(B)); B b;
b.a = 0xaaaaaaaa;
B* pb = &b;
printf("%08x\n", pb);
}

  windows输出:

8
002bfc10

  查看对象b地址内容:

002BFC10 4C
002BFC11 57
002BFC12 E7 00
002BFC14 AA
002BFC15 AA
002BFC16 AA
002BFC17 AA

  查看虚表0x00e7574c:

B::`vftable':
00E7574C 27  
00E7574D 11 E7  
00E7574F 00 00

  查看该续表中的指针0x00e71127:

B::vfun:
00E71127 E9 24 04 00 00 jmp B::vfun (0E71550h)

10: class B: public A
11: {
12: public:
13: void vfun(){};
00E71550 55 push ebp
00E71551 8B EC mov ebp,esp
00E71553 81 EC CC 00 00 00 sub esp,0CCh

  可知该虚表指向类B中的实现。

  五、虚继承父类,子类为空

#include <cstdio>

class A
{
public:
int a;
}; class B: virtual public A
{
public:
}; int main(int argc, char** argv)
{
printf("%d\n", sizeof(B)); B b;
b.a = 0xaaaaaaaa;
B* pb = &b;
printf("%08x\n", pb);
}

  windows输出:

8
0036f810

  查看对象b内存:

0036F810 48
0036F811 57
0036F812 34 01
0036F814 AA
0036F815 AA
0036F816 AA
0036F817 AA

  内存中多了0x01345748,这个是虚基类表的指针,作用于虚函数表类似后面会详细讲。查看该虚基类表:

B::`vbtable':
01345748 00 00
0134574A 00 00
0134574c 04 00
0134574e 00 00

  虚基类表内容含义后面讲。

  六、虚继承父类包含虚函数

#include <cstdio>

class A
{
public:
int a;
virtual void vfun(){};
}; class B: virtual public A
{
public:
}; int main(int argc, char** argv)
{
printf("%d\n", sizeof(B)); B b;
b.a = 0xaaaaaaaa;
B* pb = &b;
printf("%08x\n", pb);
}

  windows输出:

12
002efa64

  可见内存又增加了4字节。看下对象b内存:

002EFA64 54
002EFA65 57
002EFA66 86 00
002EFA68 4C
002EFA69 57
002EFA6A 86 00
002EFA6C AA
002EFA6D AA
002EFA6E AA
002EFA6F AA

  有两个指针,分别为虚基类表和虚函数表:

B::`vftable':
0086574C 22 11
0086574E 86 00
00865750 00 00
00865752 00 00
B::`vbtable':
00865754 00 00
00865756 00 00

  此例中子类未实现虚函数。子类实现虚函数与四类似,只是这里多了个虚基类表,就不详细讲了。

【c++内存分布系列】单继承的更多相关文章

  1. C++继承 派生类中的内存布局(单继承、多继承、虚拟继承)

    今天在网上看到了一篇写得非常好的文章,是有关c++类继承内存布局的.看了之后获益良多,现在转在我自己的博客里面,作为以后复习之用. ——谈VC++对象模型(美)简.格雷程化    译 译者前言 一个C ...

  2. C++对象内存分布(3) - 菱形继承(virtual)

    1.前言 本篇文章的全部代码样例.假设是windows上编译执行.则使用的是visual studio 2013.假设是RHEL6.5平台(linux kernal: 2.6.32-431.el6.i ...

  3. 【c++内存分布系列】虚基类表

    虚基类表相对于虚函数表要稍微难理解些,故单独提出来. 虚函数表是在对象生成时插入一个虚函数指针,指向虚函数表,这个表中所列就是虚函数. 虚基类表原理与虚函数表类似,不过虚基类表的内容有所不同.表的第一 ...

  4. 【c++内存分布系列】单独一个类

    首先要明确类型本身是没有具体地址的,它是为了给编译器生成相应对象提供依据.只有编译器生成的对象才有明确的地址. 一.空类 形如下面的类A,类里没有任何成员变量,类的sizeof值为1. #includ ...

  5. 【C++ Primer | 15】C++类内存分布

    C++类内存分布 书上类继承相关章节到这里就结束了,这里不妨说下C++内存分布结构,我们来看看编译器是怎么处理类成员内存分布的,特别是在继承.虚函数存在的情况下. 下面可以定义一个类,像下面这样: c ...

  6. C++类虚函数内存分布(这个 你必须懂)

    转自:http://www.cnblogs.com/jerry19880126/p/3616999.html C++类内存分布 书上类继承相关章节到这里就结束了,这里不妨说下C++内存分布结构,我们来 ...

  7. C++中继承 声明基类析构函数为虚函数作用,单继承和多继承关系的内存分布

    1,基类析构函数不为虚函数 #include "pch.h" #include <iostream> class CBase { public: CBase() { m ...

  8. c++内存分布之虚函数(单一继承)

    系列 c++内存分布之虚函数(单一继承) [本文] c++内存分布之虚函数(多继承) 结论 1.虚函数表指针 和 虚函数表 1.1 影响虚函数表指针个数的因素只和派生类的父类个数有关.多一个父类,派生 ...

  9. c++内存分布之虚函数(多继承)

    系列 c++内存分布之虚函数(单一继承) c++内存分布之虚函数(多继承) [本文] 结论 1.虚函数表指针 和 虚函数表 1.1 影响虚函数表指针个数的因素只和派生类的父类个数有关.多一个父类,派生 ...

随机推荐

  1. Spring @ Component 的作用

    1.@controller 控制器(注入服务) 2.@service 服务(注入dao) 3.@repository dao(实现dao访问) 4.@component (把普通pojo实例化到spr ...

  2. POJ 1270 Following Orders (拓扑排序,dfs枚举)

    题意:每组数据给出两行,第一行给出变量,第二行给出约束关系,每个约束包含两个变量x,y,表示x<y.    要求:当x<y时,x排在y前面.让你输出所有满足该约束的有序集. 思路:用拓扑排 ...

  3. Sublime Text 2 快捷键 插件配置

    一.前言之前 从设计到前端,有过一段时间是懵懵懂懂的状态,缺乏对整个职业更加深入的了解.后来混迹于各个前端大牛的博客,在各个QQ群里聆听各路大神的经验之谈,坚定了前端之路的信心.一直收藏各类精华的帖子 ...

  4. 如何防止通过IP地址访问Tomcat管理页面

    方法:建议修改webapps下面的原始文件夹的名称,比如加一个后缀: 当需要用管理页面的时候,可以将含有manager的文件夹的后缀去掉即可 manager和host-manager共2个文件夹

  5. crontab 指定执行用户

    linux下可以通过配置crontab来定时执行任务,执行体可以是一条系统命令或自己写的一个脚本,同时可以指派用户来执行.配置crontab有两种方法.方法1.使用crontab命令,例如添加一个新的 ...

  6. Dear Project Manager, I Hate You

    项目经理,我恨你,而且我知道你也恨我.我真的不理解,你究竟是做什么的. 你是一个多么独特的角色呀,几乎每个公司都要雇用你这样的人.可在不管大大小小的项目中,你与其说是帮忙,不如说是添乱.我坚信,大部分 ...

  7. 从一点儿不会开始——Unity3D游戏开发学习(二) ——GUI控件之Button

    一些废话 我在上一篇“一点儿不会”的系列随笔中说大概一周会发个2~3篇关于Unity的学习笔记.可这就两周过去了,我还停留在一篇的进度上,主要是这两周发生了一些事情导致我更新缓慢.其实截至目前为止,上 ...

  8. 2014-9-17二班----9 web project

    http://localhost:8080/rwkj1/indexServlet             跳转                    http://localhost:8080/rwk ...

  9. 格林治时间,也就是返回从 UTC 1970 年 1 月 1 日午夜开始经过的毫秒数。

    格林治时间,也就是返回从 UTC 1970 年 1 月 1 日午夜开始经过的毫秒数. (* Delphi获取13位格林治时间实现方法, 与java中的java.lang.System.currentT ...

  10. sudo和su

    su命令就是切换用户的工具 sudo 授权许可使用的su,也是受限制的su 1. sudo 的适用条件 由于su 对切换到超级权限用户root后,权限的无限制性,所以su并不能担任多个管理员所管理的系 ...