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布局的更多相关文章

  1. 【深度探索C++对象模型】data语义学

    class X{}; class Y :public virtual X{}; class Z :public virtual X{}; class A :public Y, public Z{}; ...

  2. c++对象模型以及内存布局的研究

    先引出问题,看一段代码: #include <iostream> using namespace std; class A { }; class B { public: B() {} ~B ...

  3. 嵌入式开发软件环境:uboot、kernel、rootfs、data布局分析

    uboot+linux的整体方案 开发板的datasheet中都有详细的地址空间的划分,其中比较重要的两块是:DDR地址空间和Flash地址空间.DDR空间是系统和应用的运行空间,一般由linux系统 ...

  4. 【深入探索c++对象模型】data语义学二

    单一继承中,base class 和derived class的对象都是从相同的地址开始,其间差异只在于derived class比较大,用以容纳自己的nonstatic members. 若vptr ...

  5. C++对象模型的那些事儿之三:默认构造函数

    前言 继前两篇总结了C++对象模型及其内存布局后,我们继续来探索一下C++对象的默认构造函数.对于C++的初学者来说,有如下两个误解: 任何class如果没有定义default constructor ...

  6. 深入探索C++对象模型(1) 关于对象(思维导图)

    通过上面整个关于对象的基础知识框架,我们来分析两个例子,看一下在内存中,对象究竟长什么样.   Demo1:C++对象模型的内存布局 class Point { public: Point( floa ...

  7. 【深度探索c++对象模型】关于对象

    Linux进程的五个段 BSS段:BSS段(bss segment)通常是指用来存放程序中未初始化的全局变量的一块内存区域.BSS是英文Block Started by Symbol的简称.BSS段属 ...

  8. C++对象模型的那些事儿之二:对象模型(下)

    前言 上一篇博客C++对象模型的那些事儿之一为大家讲解了C++对象模型的一些基本知识,可是C++的继承,多态这些特性如何体现在对象模型上呢?单继承.多重继承和虚继承后内存布局上又有哪些变化呢?多态真正 ...

  9. 从JSON中自动生成对应的对象模型

    编程的乐趣和挑战之一,就是将体力活自动化,使效率成十倍百倍的增长. 需求 做一个项目,需要返回一个很大的 JSON 串,有很多很多很多字段,有好几层嵌套.前端同学给了一个 JSON 串,需要从这个 J ...

随机推荐

  1. 10个加速Table Views开发的Tips(转)

    本文由CocoaChina译者yake_099(博客)翻译,作者:David McGraw原文:10 Actionable Performance Tips To Speed Up Your Tabl ...

  2. MySQL被Oracle并购后的409个日日夜夜

    2009年4月20日,Oracle并购了Sun,这也意味着MySQL归属到甲骨文的旗下.四百多天过去了,究竟这场并购结局如何?请看本文. 去年对Sun的收购,让甲骨文顺利的将一个潜在的对手MySQL收 ...

  3. 多核CPU利用测试

      一直在想程序上是否特意让线程在指定的CPU上去运行,这样可以提高运行效率,所以特地写个代码让CPU使用率画正弦曲线的实验,我使用的是AMD X4 641的CPU,为四核四线程的片子. 代码如下 # ...

  4. 你好,C++(7)第三部分 C++世界众生相 3.2.1 变量的定义与初始化

    第3部分 C++世界众生相 在听过了HelloWorld.exe的自我介绍,完成了与C++世界的第一次亲密接触后,大家是不是都急不可待地想要一试身手,开始编写C++程序了呢?程序的两大任务是描述数据和 ...

  5. webBrowser(网络转载)

    C#WebBrowser控件使用教程与技巧收集--苏飞收集 先来看看常用的方法 [C#] 纯文本查看 复制代码 ? 01 02 03 04 05 06 07 08 09 10 11 12 13 14 ...

  6. ul ol 列表的样式的控制

    ul( Unordered List)无序列表 ol(Ordered List)有序列表 列表的样式: 列表原有符号.自定义图形符号.符号显示位置. 1.列表符号 是显示于每一个列表项目前的符号标识. ...

  7. Python自动化运维之16、线程、进程、协程、queue队列

    一.线程 1.什么是线程 线程是操作系统能够进行运算调度的最小单位.它被包含在进程之中,是进程中的实际运作单位. 一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行 ...

  8. Day6 反射、模块、正则表达式和算法

    递归完成阶乘 def func(num): if num == 1: return 1 return num * func(num - 1) x = func(7) print(x) 反射 commo ...

  9. twisted(1)--何为异步

    早就想写一篇文章,整体介绍python的2个异步库,twisted和tornado.我们在开发python的tcpserver时候,通常只会用3个库,twisted.tornado和gevent,其中 ...

  10. 使用飞信api接口实现短信发送(只能发送好友)

    找了很久才找到一个能用的飞信API接口(http://quanapi.sinaapp.com/fetion.php?u=飞信登录手机号&p=飞信登录密码&to=接收飞信的手机号& ...