一个空的class:如

class X{} ;

sizeof(X)==1;

sizeof为什么为1,他有一个隐晦的1 byte,那是被编译器安插进去的一个char,这使得class2的两个objects得以在内存中配置独一无二的地址:

X a,b;

if(&a==&b) cerr<<"yipes!"<<endl;

class X{};
class Y:public virtual X{};
class Z:public virtual X{};
class A:public Y,public Z{}; cout<<"sizeof(X):"<<sizeof(X)<<endl;
cout<<"sizeof(Y):"<<sizeof(Y)<<endl;
cout<<"sizeof(Z):"<<sizeof(Z)<<endl;
cout<<"sizeof(A):"<<sizeof(A)<<endl;

我的vs结果是1 ,4,4,8.

但是让人搞不懂的是Y、Z的大小。主要大小受三个因素的影响:

  • 语言本身所造成的额外负担,当语言支持虚基类virtual base class的时候,就导致一个额外的负担,这个一般反映在某种形式的指针身上,它或者指向virtual base class subobject,或者指向一个相关表格。
  • 编译器对于特殊情况所提供的优化处理,因为class X有1 byte的大小,这样就出现在了class Y和class Z身上。这个主要视编译器而定,比如某些存在这个1byte但是有些编译器就将他忽略了(因为已经用虚指针了所以这个1byte就可以不用作为内存中的一个定位)。这种情况是对empty virtual base的特殊处理,如VS。
  • Alignment的限制,就是所谓的对齐操作,比如你现在占用5bytes编译器为了更有效率地在内存中存取就将其对齐为8byte。
  • 下面说明在vs2010中的模型,因为有了虚指针后所以1byte就不用了,所以class Y和class Z的大小就是4bytes,如下图:

现在你觉得class A的大小应该是多少呢?一个虚基类子对象只会在派生类中存在一份实体,不管他在继承体系中出现多少次,所以公用一个1byte的classX实体,再加上class Y和class Z这样就有9bytes,如果有对齐的话就是12bytes但是vs2010中省略了那1byte所以就不存在对齐就直接是8bytes。谜底终于揭开了!!!

Data Member的绑定:the binding of a data member

Data Member的布局

类的static data member会放在程序的数据段(data segment)。

c++ standard要求,在同一个access section中,member的排列只需符合”较晚出现的members在class object中有较高的地址“这一条件即可。也就是说,各个members并不一定得连续排列。什么东西可能会介于被声明的members之间呢?members的边界调整(alignment)可能就需要填补一些bytes。

不同的access section的数据们放置没有强制的前后关系。vptr的放置也没有强制规定。

Data Member的存取

1)对于static data member
      每次程序取用static member,就会被内部转换为对该唯一的extern实体的直接参考操作。存取static members并不需要通过class object。对于继承而来的static member其存取路径也是同样直接。(因为static members只存在唯一的一份实体)
 
(如何有2个classes,每一个都声明了一个static member freelist;那么都被放在程序的data segment时,就会导致冲突,编译器的解决办法是暗中对每一个static data member编码(name-mangling),以获得一个独一无二的程序识别代码。任何name-mangline都有2个要点:
1.一种算法,推导出独一无二的名称
2.独一无二的名称可以轻易被推导回原来的名称。
(2)对于nonstatic data member
      每一个nonstatic data member的偏移量offset,在编译时期即可获知。(派生自单一或多重继承串链也一样)。
而当虚继承时,虚继承将为“经由base class subobject 存取 class members”导入一层新的间接性。
 
(2)对于nonstatic data member
      每一个nonstatic data member的偏移量offset,在编译时期即可获知。(派生自单一或多重继承串链也一样)。
nonstatic data member直接存放在class object之中,除非经由明确explicti或暗喻的implicit的class object,没有办法直接存取他们。只要程序员在一个member function直接处理一个nonstatic data member,所谓的”implicit class object“就会发生。例如:
Point3D Point3D::translate(const Point3D &pt){
   x+=pt.x;
 y+=pt.y;
 z+=pt.z;
}
表面上所看到的对于x,y,z的直接存取,事实上是经由一个”implicit class object“(有this指针表达)完成,事实上这个函数的参数是:
Point3D Point3D::translate(Point3d * const thisconst Point3D &pt){
   this->x+=pt.x;
this-> y+=pt.y;
 this->z+=pt.z;
}
欲对一个nonstatic data member进行存取操作,编译器需要把class object的起始地址加上data member的偏移量(offset)。
举个例子,如:
class Point3d{
public:
 //..
private:
 float x;
 static List<Point#d*> *freeList;
 float y;
 static const int chunkSize=250;
 float z;
}
Point3d orgin;
 
origin._y=0.0;
那么地址&origin._y将等于
&origin+(&Point3d::_y-1);
请注意-1操作,指向data member的指针,其offset值总是被加上1,这样可以是编译系统区分出”一个指向data member的指针,用以指出class的第一个member”和“一个指向data member的指针,没有指出任何member”两种情况。
  每一个nonstatic data member的偏移量(offset)在编译时期即可货值,甚至一个member属于一个base class subobject(派生自单一或多重继承串链)也是一样,因此,存放一个nonstatic data member,其效率和存取一个c struct member或一个nondervied class的member是一样的。

必须通过对象才能访问nonstatic data member(要不然访问的是谁的data member呢)。方法为对象的地址加上data member的offset就是这个data member的地址。

但在有虚拟继承的情况下,由于“经由base class subject存取class member”导入一层新的间接性,访问的时候,会有不同。考虑如下代码:

Point3d origin, *pt;

origin.x = 0;

pt->x;

由于origin一定是Point3d类型,所以origin.x编译时即可确定其offset。

从origin和pt存取有何差异?
      答:当Point3d是一个derived class,而在其继承结构中有一个virtual base class,并且被存取的member是一个从该virtual base class继承而来的member时,有差异。
      从pt存取,这时我们不知道pt指向哪一种class type,即无法知道编译时期这个member真正的offset位置,这个存取操作必须延迟至执行期,经由一个额外的间接引导,才能够解决。存取速度比较慢一些。从origin存取,origin的类型是明确的,members的offset位置在编译时期就固定了
 
 
继承与Data Member
在c++继承模型中,一个dervied class object所表现的东西,是其自己的member是加上其base class member的总和。在大部分编译器中,base class member总是先出现,但属于virtual base class的除外(一般而言,任何规则一旦碰上virtual base class就没辙了,这里也不例外)。
 

《深度探索c++对象模型》chapter3 Data语意学的更多相关文章

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

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

  2. c++学习书籍推荐《深度探索C++对象模型》下载

    百度云及其他网盘下载地址:点我 百度云及其他网盘下载地址:点我 编辑推荐 如果你是一位C++程序员,渴望对于底层知识获得一个完整的了解,那么这本<深度探索C++对象模型>正适合你 作者简介 ...

  3. [读书系列] 深度探索C++对象模型 初读

    2012年底-2014年初这段时间主要用C++做手游开发,时隔3年,重新拿起<深度探索C++对象模型>这本书,感觉生疏了很多,如果按前阵子的生疏度来说,现在不借助Visual Studio ...

  4. 拾遗与填坑《深度探索C++对象模型》3.3节

    <深度探索C++对象模型>是一本好书,该书作者也是<C++ Primer>的作者,一位绝对的C++大师.诚然该书中也有多多少少的错误一直为人所诟病,但这仍然不妨碍称其为一本好书 ...

  5. 拾遗与填坑《深度探索C++对象模型》3.2节

    <深度探索C++对象模型>是一本好书,该书作者也是<C++ Primer>的作者,一位绝对的C++大师.诚然该书中也有多多少少的错误一直为人所诟病,但这仍然不妨碍称其为一本好书 ...

  6. 深度探索C++对象模型

    深度探索C++对象模型 什么是C++对象模型: 语言中直接支持面向对象程序设计的部分. 对于各个支持的底层实现机制. 抽象性与实际性之间找出平衡点, 需要知识, 经验以及许多思考. 导读 这本书是C+ ...

  7. 《深度探索C++对象模型》读书笔记(一)

    前言 今年中下旬就要找工作了,我计划从现在就开始准备一些面试中会问到的基础知识,包括C++.操作系统.计算机网络.算法和数据结构等.C++就先从这本<深度探索C++对象模型>开始.不同于& ...

  8. 读书笔记《深度探索c++对象模型》 概述

    <深度探索c++对象模型>这本书是我工作一段时间后想更深入了解C++的底层实现知识,如内存布局.模型.内存大小.继承.虚函数表等而阅读的:此外在很多面试或者工作中,对底层的知识的足够了解也 ...

  9. 柔性数组-读《深度探索C++对象模型》有感 (转载)

    最近在看<深度探索C++对象模型>,对于Struct的用法中,发现有一些地方值得我们借鉴的地方,特此和大家分享一下,此间内容包含了网上搜集的一些资料,同时感谢提供这些信息的作者. 原文如下 ...

  10. 柔性数组-读《深度探索C++对象模型》有感

    最近在看<深度探索C++对象模型>,对于Struct的用法中,发现有一些地方值得我们借鉴的地方,特此和大家分享一下,此间内容包含了网上搜集的一些资料,同时感谢提供这些信息的作者. 原文如下 ...

随机推荐

  1. 如何让Windows程序只运行一个程序实例?

    要实现VC++或者MFC只运行一个程序实例,一般采用互斥量来实现,即首先用互斥量封装一个只运行一个程序实例的函数接口: HANDLE hMutex = NULL; void MainDlg::RunS ...

  2. Android(java)学习笔记194:ListView编写步骤(重点)

    1.ListView在我们的手机android编写程序中使用是十分广泛的,比如如下图中 短信 和 手机设置 都是ListView的效果: 手机设置:             短信:    2.正因为这 ...

  3. Java线性表的排序

    Java线性表的排序 ——@梁WP 前言:刚才在弄JDBC的时候,忽然觉得order-by用太多了没新鲜感,我的第六感告诉我java有对线性表排序的封装,然后在eclipse里随便按了一下“.” ,哈 ...

  4. ubuntu 13.04 xrdp 远程桌面连接问题[转载]

    本人ubuntu12.04,遇到了同样的问题,用一下方法解决了,mark一下. ubuntu 13.04 xrdp 远程桌面连接问题. win 7 远程桌面连接 ubuntu desktop 有几种办 ...

  5. (六)Struts2 国际化

    所有的学习我们必须先搭建好Struts2的环境(1.导入对应的jar包,2.web.xml,3.struts.xml) 第一节:国际化简介 国际化(Internationlization),通俗地讲, ...

  6. LINQ 101——分组、Set、转换、Element

    一.Grouping(分组) 例1:对于0-9数按被3整除的结果分组 代码: static void Linq1() { , , , , , , , , , }; var numModBy3 = fr ...

  7. (转) c# ExecuteNonQuery() 返回值 -1

    这是之前我遇到问题,在网上找解决方法时找到的,当时复制到txt文档了,今天整理笔记又看到了,贴出来,便于以后查阅.原文的作者没记住~~ 查询某个表中是否有数据的时候,如果用ExecuteNonQuer ...

  8. 时区之痒 - 从手机GPS模块获取的时间,真的是北京时间么?

    去年互联网地图行业开始引入众包模式,国内比较大的地图商,比如四维图新.高德地图.百度地图纷纷开始推出UGC应用,众包给用户采集门址.公交站等信息,并按照工作量给与采集者一定的回报.我曾经玩过某德推出的 ...

  9. 生成dll文件的示例

    看了好多网上写的关于dll文件生成和实用的资料发现多尔不全,都是抄来抄去,有的干脆就是搬用msdn上的原文,实在没有创意和可看的东西.于是本着学和实用的目的自己实践的东西分享给大家. 大前提:使用VS ...

  10. 读书笔记之 - javascript 设计模式 - 享元模式

    本章探讨另一种优化模式-享元模式,它最适合于解决因创建大量类似对象而累及性能的问题.这种模式在javascript中尤其有用,因为复杂的javascript代码很快就会用光浏览器的所有可用内存,通过把 ...