c++对象模型之Data布局
Data语意学
class X{};
class Y : publicvirtual X {};
class Z : publicvirtual X {};
class A : publicY, public Z {};
sizeof(X) = 1,sizeof(Y) = 4, sizeof(Z) = 4, sizeof(A) = 8。visualc++6.0上測试结果(对emptyvirtual base class 有特殊处理的编译器)
反之则相应的结果为1。8。8,12
其实Y,Z的大小受三个因素的影响:
1.语言本身所造成的额外负担
2.编译器对于特殊情况所提供的优化处理
3.Alignment限制
有特殊处理情况下对象布局例如以下:
无特殊处理情况对象布局例如以下:
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">
对于nonstaticdata members直接存放在每个classobject之中。对于继承而来的nonstatic data members也是一样,只是并没有强制定义其间的排列顺序。至于staticdata members,则被放置在程序的一个globaldata segment中。不会影响个别的classobject的大小。
一Data Member的绑定
1.Datamembers绑定
extern int x;
class Point3d
{
public:
//对函数本身的分析将延迟至class声明的右边大括号出现才開始
float X() const { return x;}
//....
private:
float x;
};
对memberfunctions本身的分析。会直到整个class的声明都出现了才開始即对于X()函数返回的x将是类中的定义的x。
2.Membersfunctions的argumentlist
typedef int length;
class Point3d
{
//typedef char length;
public:
//length被决议为global
//_val被决议为Point3d::_val
void mumble(length val) { _val = val; }
length mumble() {return _val;}
private:
//length必须在“本class对它的第一个參考操作”之前被看见
//这种声明将使先前的參考操作不合法
typedef char length;
length _val;
};
上述的这样的语言状况,仍然须要某种防御性程序风格:情始终把“nestedtype声明”放在class的起始处。
二Data Member的布局
Nostatic data members 在classobject中的排列顺序将和其被生命的顺序一样,不论什么中间介入的staticdata members都不会被放进对象布局之中。
C++ standard要求,在同一个accesssection(也就是private、public、protected等区段)中,members的排列仅仅需符合“较晚出现的members在classobject中有较高的地址”这一条件就可以。
C++ standerd也同意编译器将多个accesssection之中的data members自由排列,不必在乎它们出如今class声明中的次序。
值得注意的是accesssection的多寡并不会招来额外的负担。比如在一个section中声明8个members。或是在8个section中总共声明8个members,得到的object大是一样的。
三Data Member的存取
1.Staticdata members
存取staticmembers并不须要通过class object;若取一个staticdata memb的
地址。会得到一个指向其classmember的指针,由于static member并不内含在一个classobject中。
比如:
&Point3d::chunkSize;
会得到类型例如以下的内存地址:
const int*
2.NonstaticData Members
Nonstatic data members 直接存放在每个classobject之中。除非经由明白
(explic)的或暗喻(implicit)的classobject。没有办法直接存取它们。
在member function 里面编译器会自己主动合成this指针。
欲对一个nonstaticdata member进行存取操作,编译器须要把classobject的起始地址加上data member的偏移量(offset)。每个nonstaticdata member的offset在编译时期就可以获知。
Point3d origin, *pt;
Origin.x = 0.0;
pt->x = 0.0;
两种存取方式有什么重大的差异?答案是“当Point3d是一个derivedclass。而在其继承结构中有一个virtual base class,而且被存取的member(比如本例中的x)是一个从该virtualbase class继承而来的member时,就会有重大的差异。
四继承与Data member
1.仅仅有继承没有多态
在c++继承模型中,一个derivedclass object所表现出来的东西。是其自己的members加上其baseclass members的总和。至于derivedclass members 和baseclass members的排列次序并没有强制指定,通常是基类在前。
把原本不相干的两个class凑成一对“type/subtype”会犯的错误有:1.可能会反复设计一些同样操作的函数;2.把一个class分解为两层或很多其它层。有可能会为了“表现class体系之抽象化”而膨胀所需空间。C++语言保证“出如今derived class中的baseclass subobject有其完整原样性”。
class Concrete
{
private:
int val;
char c1;
char c2;
char c3;
};
sizeof(Concrete)= 8
将Concrete分裂为三层结构:
class Concrete1
{
Public:
//….
Private:
int val;
char bit1;
};
class Concrete2
{
Public:
//….
Private:
char bit2;
};
class Concrete3
{
Public:
//….
Private:
char bit3;
};
能够得出sizeof(Concrete3)=16,比原先设计的多了一倍。对象布局例如以下:
关于base classsubobject在derivJedclass中保持原样原因解释
2.加上多态
多态带来的空间和存取时间的额外负担:
①导入一个virtualtable,用来存放在它所声明的每个virtual function的地
址。这个table的元素数目一般而言是被声明的virtualfunctions的数目,再加上一个或两个slots。
②在每个classobject中导入一个vptr,提供运行期间的链接,使每个
object可以找到对应的virtualtable。
③加强constructor,使它可以为vptr设定初值,让它指向class所相应的virtual
table。
④加强destructor,使它可以抹消“指向class之相关virtualtable”的vptr。
记
住destructor的调用次序是反向的:从derivedclass到base class。
全部的编译器不是吧vptr放在对象的头部,就是放在对象的尾部。
五指向Data Members的指针
/*
Pointer to Data Members
*/
#include<iostream>
usingnamespace std;
classPoint3d
{
virtual ~Point3d();
public:
static Point3d origin;
float x, y, z;
};
intmain()
{
//类型为floatPoint3d::*而并非float*
printf("&Point3d::x =%p\n", &Point3d::x);
printf("&Point3d::y =%p\n", &Point3d::y);
printf("&Point3d::z =%p\n", &Point3d::z);
}
#include<iostream>
usingnamespace std;
structPoint
{
int x, y;
double d1, d2;
}
intAdd(Point arr[], int size, int Point::*p)
{
int sum = 0;
for(int i = 0; i < size; i ++)
sum += arr[i].*p;
return sum;
}
doubleAdd1(Point arr[], int size, double Point::*p)
{
int sum = 0;
for(int i = 0; i < size; i ++)
sum += arr[i].*p;
return sum;
};
intmain()
{
Point pp[3] = { {1,2,1.0,2.0},{3,4,1.0,2.0}, {5,6,1.0,2.0} };
cout<<Add(pp, 3,&Point::x)<<endl<<Add(pp, 3, &Point::y)<<endl;
cout<<Add1(pp, 3,&Point::d1)<<endl<<Add1(pp, 3, &Point::d2)<<endl;
}
c++对象模型之Data布局的更多相关文章
- 【深度探索C++对象模型】data语义学
class X{}; class Y :public virtual X{}; class Z :public virtual X{}; class A :public Y, public Z{}; ...
- c++对象模型以及内存布局的研究
先引出问题,看一段代码: #include <iostream> using namespace std; class A { }; class B { public: B() {} ~B ...
- 嵌入式开发软件环境:uboot、kernel、rootfs、data布局分析
uboot+linux的整体方案 开发板的datasheet中都有详细的地址空间的划分,其中比较重要的两块是:DDR地址空间和Flash地址空间.DDR空间是系统和应用的运行空间,一般由linux系统 ...
- 【深入探索c++对象模型】data语义学二
单一继承中,base class 和derived class的对象都是从相同的地址开始,其间差异只在于derived class比较大,用以容纳自己的nonstatic members. 若vptr ...
- C++对象模型的那些事儿之三:默认构造函数
前言 继前两篇总结了C++对象模型及其内存布局后,我们继续来探索一下C++对象的默认构造函数.对于C++的初学者来说,有如下两个误解: 任何class如果没有定义default constructor ...
- 深入探索C++对象模型(1) 关于对象(思维导图)
通过上面整个关于对象的基础知识框架,我们来分析两个例子,看一下在内存中,对象究竟长什么样. Demo1:C++对象模型的内存布局 class Point { public: Point( floa ...
- 【深度探索c++对象模型】关于对象
Linux进程的五个段 BSS段:BSS段(bss segment)通常是指用来存放程序中未初始化的全局变量的一块内存区域.BSS是英文Block Started by Symbol的简称.BSS段属 ...
- C++对象模型的那些事儿之二:对象模型(下)
前言 上一篇博客C++对象模型的那些事儿之一为大家讲解了C++对象模型的一些基本知识,可是C++的继承,多态这些特性如何体现在对象模型上呢?单继承.多重继承和虚继承后内存布局上又有哪些变化呢?多态真正 ...
- 从JSON中自动生成对应的对象模型
编程的乐趣和挑战之一,就是将体力活自动化,使效率成十倍百倍的增长. 需求 做一个项目,需要返回一个很大的 JSON 串,有很多很多很多字段,有好几层嵌套.前端同学给了一个 JSON 串,需要从这个 J ...
随机推荐
- asp.net用Zxing库实现条形码输出的具体实现
首先要在项目中添加zxing.dll引用(zxing.dll下载地址http://www.jb51.net/dll/zxing.dll.html) 其次就是建立aspx文件,在后台中代码如下 复制代码 ...
- NPOI对excel文件的导入导出
现理解:将一个Excel文件(工作簿-IWorkBook)看做是一个你要操作的对象,每个工作簿包含多个工作表(ISheet)对象,每个工作表中又包含多个行对象(IRow),每行又包含多个单元格(ICe ...
- WPF 依赖属性与依赖对象
在介绍依赖属性之前,我先介绍下属性的历史 属性的历史: 早期C++的类中,只有字段及方法,暴露数据靠的是方法, 但是字段直接暴露会不安全,所以才用方法来暴露,在设置的时候加些约束,在MFC中 ...
- ES5严格模式
http://www.cnblogs.com/snandy/p/3428171.html 介绍了由ECMA262规范定义的Javascript标准,旨在改善错误检查功能并且标识不会延续到未来js版本的 ...
- 动态加载下拉框列表并添加onclick事件
1. js动态加载元素并设置属性 摘自(http://www.liangshunet.com/ca/201408/336848696.htm) <div id="parent&quo ...
- Spring+SpringMVC+Mybatis+MAVEN+Eclipse+项目完整环境搭建
1.新建一个Maven项目,创建父项目. 2.创建子项目模块 3.创建javaWeb项目 4.创建后的项目目录结构 5.Maven文件配置 parent父项目pom.xml文件配置 <?xml ...
- 关于canvas 易忘属性
globalAlpha=1//表示全局的一个透明度值 默认值是1 globalCompositeOperation // 默认值="source-over"(Default)
- jQuery操作cookie
验证jquery的cookie插件时才知道原先文件一直在桌面上放着执行发现没有效果,文件必须放在web服务器下面执行才会生效,晕菜! $.cookie(name,value,{expires: 7,p ...
- HTml <meta>标签的使用(重要)
<meta> 元素可提供有关页面的元信息(meta-information),比如针对搜索引擎和更新频度的描述和关键词. 1.设置网页字符编码 <meta http-equiv=&q ...
- Python自动化运维之17、Python操作 Memcache、Redis、RabbitMQ
一.Memcached Memcached 是一个高性能的分布式内存对象缓存系统,用于动态Web应用以减轻数据库负载.它通过在内存中缓存数据和对象来减少读取数据库的次数,从而提高动态.数据库驱动网站的 ...