C++类的内存结构
简单类
class Base
{
int a;
int b;
public:
void CommonFunction();
};

简单类继承
class DerivedClass: public Base
{
int c;
public:
void DerivedCommonFunction();
};

带有虚函数的类
class Base
{
int a;
int b;
public:
void CommonFunction();
void virtual VirtualFunction();
};

虚函数类继承
没有复写的继承
class DerivedClass: public Base
{
int c;
public:
void DerivedCommonFunction();
void virtual VirtualFunction();
};

复写的继承
class DerivedClass1 : public Base
{
int c;
public:
void DerivedCommonFunction();
void virtual VirtualFunction();
void virtual VirtualFunction2();
};

多重继承
class Base
{
int a;
int b;
public:
void CommonFunction();
void virtual VirtualFunction();
};
class DerivedClass1: public Base
{
int c;
public:
void DerivedCommonFunction();
void virtual VirtualFunction();
};
class DerivedClass2 : public Base
{
int d;
public:
void DerivedCommonFunction();
void virtual VirtualFunction();
};
class DerivedDerivedClass : public DerivedClass1, public DerivedClass2
{
int e;
public:
void DerivedDerivedCommonFunction();
void virtual VirtualFunction();
};
内存分布从父类到子类,依次如下:
Base中有一个虚表指针

DerivedClass1继承了Base,内存排布是先父类后子类。

DerivedClass2的情况是类似于DerivedClass1的。

DerivedDerivedClass,由外向内看,它并列地排布着继承而来的两个父类DerivedClass1与DerivedClass2,还有自身的成员变量e。DerivedClass1包含了它的成员变量c,以及Base,Base有一个0地址偏移的虚表指针,然后是成员变量a和b;DerivedClass2的内存排布类似于DerivedClass1,注意到DerivedClass2里面竟然也有一份Base。

这里有两份虚表了,分别针对DerivedClass1与DerivedClass2,在&DerivedDericedClass_meta下方的数字是首地址偏移量,靠下面的虚表的那个-16表示指向这个虚表的虚指针的内存偏移,这正是DerivedClass2中的{vfptr}在DerivedDerivedClass的内存偏移。

虚继承
class DerivedClass1: virtual public Base
{
int c;
public:
void DerivedCommonFunction();
void virtual VirtualFunction();
};
class DerivedClass2 : virtual public Base
{
int d;
public:
void DerivedCommonFunction();
void virtual VirtualFunction();
};
class DerivedDerivedClass : public DerivedClass1, public DerivedClass2
{
int e;
public:
void DerivedDerivedCommonFunction();
void virtual VirtualFunction();
};
Base类没有变化

DerivedClass1就已经有变化了,原来是先排虚表指针与Base成员变量,vfptr位于0地址偏移处;但现在有两个虚表指针了,一个是vbptr,另一个是vfptr。vbptr是这个DerivedClass1对应的虚表指针,它指向DerivedClass1的虚表vbtable,另一个vfptr是虚基类表对应的虚指针,它指向vftable。

下面列出了两张虚表,第一张表是vbptr指向的表,8表示{vbptr}与{vfptr}的偏移;第二张表是vfptr指向的表,-8指明了这张表所对应的虚指针位于内存的偏移量。

DerivedClass2的内存分布类似于DerivedClass1,同样会有两个虚指针,分别指向两张虚表(第二张是虚基类表)。

下面来仔细看一下DerivedDerivedClass的内存分布,这里面有三个虚指针了,但base却只有一份。第一张虚表是内含DerivedClass1的,20表示它的虚指针{vbptr}离虚基表指针{vfptr}的距离,第二张虚表是内含DerivedClass2的,12表示它的虚指针{vbptr}离虚基表指针{vfptr}的距离,最后一张表是虚基表,-20指明了它对应的虚指针{vfptr}在内存中的偏移。


虚继承的作用是减少了对基类的重复,代价是增加了虚表指针的负担(更多的虚表指针)。
下面总结一下(当基类有虚函数时):
1. 每个类都有虚指针(vptr, virtual table pointer)和虚函数表(vtbl, virtual table);
2. 如果不是虚继承,那么子类将父类的虚指针继承下来,并指向自身的虚函数表(发生在对象构造时)。有多少个虚函数,虚函数表里面的项就会有多少。多重继承时,可能存在多个的基类虚函数表与虚指针;
3. 如果是虚继承,那么子类会有两份虚指针,一份指向自己的虚函数表,另一份指向基类虚函数表,多重继承时基类虚函数表与基类虚指针有且只有一份。
C++类的内存结构的更多相关文章
- Java内存结构、类的初始化、及对象构造过程
概述 网上关于该题目的文章已经很多,我觉得把它们几个关联起来讲可能更好理解一下.与其它语言一样,它在执行我们写的程序前要先分配内存空间,以便于存放代码.数据:程序的执行过程其实依然是代码的执行及数据的 ...
- C++类对应的内存结构
提示1:对“内存结构”表示有疑问或不解的,先参考: http://blog.csdn.net/guogangj/archive/2007/05/25/1625199.aspx, 本文使用的表示方法和V ...
- 关于结构体和C++类的内存地址问题
关于结构体和C++类的内存地址问题 今天终于有时间写点东西了~ 太爽了 *_* 很多人都知道C++类是由结构体发展得来的,所以他们的成员变量(C语言的结构体只有成员变量)的内存分配机制是一样 ...
- jvm系列(二):JVM内存结构
JVM内存结构 所有的Java开发人员可能会遇到这样的困惑?我该为堆内存设置多大空间呢?OutOfMemoryError的异常到底涉及到运行时数据的哪块区域?该怎么解决呢?其实如果你经常解决服务器性能 ...
- JVM之内存结构
JVM是按照运行时数据的存储结构来划分内存结构的.JVM在运行Java程序时,将他们划分成不同格式的数据,分别存储在不同的区域,这些数据就是运行时数据.运行时数据区域包括堆,方法区,运行时常量池,程序 ...
- Oracle之内存结构(SGA、PGA)
一.内存结构 SGA(System Global Area):由所有服务进程和后台进程共享: PGA(Program Global Area):由每个服务进程.后台进程专有:每个进程都有一个PGA. ...
- 浅析JVM内存结构和6大区域(转)举例非常好
内存作为系统中重要的资源,对于系统稳定运行和高效运行起到了关键的作用,Java和C之类的语言不同,不需要开发人员来分配内存和回收内存,而是由JVM来管理对象内存的分配以及对象内存的回收(又称为垃圾回收 ...
- [转]oracle学习入门系列之五内存结构、数据库结构、进程
原文地址:http://www.2cto.com/database/201505/399285.html 1 Oracle数据库结构 关于这个话题,网上一搜绝对一大把,更别提书籍上出现的了,还有很多大 ...
- 虚函数列表: 取出方法 // 虚函数工作原理和(虚)继承类的内存占用大小计算 32位机器上 sizeof(void *) // 4byte
#include <iostream> using namespace std; class A { public: A(){} virtual void geta(){ cout < ...
随机推荐
- 【Teradata SQL】使用SQL将多个逗号分隔改为一个逗号分隔
1.问题说明: //将如下字符串改为一个逗号分隔 张三,李四,王五,,,,,,六,,,,其,,,,,,,,,,,把 ==> 张三,李四,王五,六,其,把 2.解决方法 sel oreplace( ...
- Nginx使用教程(八):使用Nginx缓存之Memcached缓存
使用Memcache <br\>Memcache是一个通用的内存缓存系统. 它通常用于加速缓慢的数据访问. NGINXmemcached模块提供各种指令,可以配置为直接访问Memcache ...
- CF 331 E. Biologist
CF 331 E. Biologist 题目描述 题目大意:有\(n\)个点,初始时每个点为黑色或者白色,你可以花费\(v_i\)的代价将一个点反色.然后你有许多计划,每个计划要求一个点集中的所有点为 ...
- Rancher2-----了解什么是rancher以及简单部署
个人理解:就是相当于openstack的图形化界面,或者说应用程序的图形化界面,rancher功能就是在图形化界面去管理容器,包括运行容器,创建网络,存储等:rancher有个应用商店,可以根据自己的 ...
- BeautifulSoup类
from bs4 import BeautifulSoup soup1 = BeautifulSoup("<html>data</html>"," ...
- [matlab] 5.字符运算与微积分
首先介绍一下matlab里的符号计算 符号变量可以看成是数学中含参数 的表达式中的参数 matlab能进行像(a+b)(a-b)=a^2-b^2这样的计算 要进行符号计算首先要定义符号变量 定义符号对 ...
- 转://Oracle 事务探索与实例(一)
一数据库版本 SYS@LEO1>select* from v$version; BANNER -------------------------------------------------- ...
- MYSQL学习笔记——sql语句优化工具
优化sql:思路: 使用explan->先查询type类型看看是all还是ref,然后判断 possible_keys (显示可能应用在这张表中的索引, 一个或多个.查询涉及到的字段是若存在索引 ...
- zabbix 应用监控作业笔记 ansible-playbook
目录 目录结构 zabbix-web.yaml zabbix-backup.yaml zabbix-nfs.yaml zabbix-mysql.yaml zabbix-server.yaml zabb ...
- apt-get update 更新 ubuntu时出现Hash sum mismatch的原因及解决方法
$ sudo apt-get update ...... Hit http://mirrors.163.com trusty/main Sources ...