《深度探索C++对象模型》—关于对象(Object Lessons)

前言

“本书是由一位编译器设计者针对中高级C++程序员所写的。隐藏在这本书背后的假设是,程序员如果了解C++对象模型,就可以写出比较没有错误倾向而且比较有效率的代码。”

正是因为在实际编程中吃了亏,所以才觉得读这本书是十分有必要的,比如之前的一篇博文:

http://blog.csdn.net/jiange_zh/article/details/51871782

如果读过这本书,想必也就不会有所困惑了。

下面是我个人的一些读书笔记,大部分知识可能是从书中摘录下来的,仅方便日后自己快速回顾查阅。

第1章 关于对象(Object Lessons)

加上封装后的布局成本

C++在布局以及存取时间上主要的额外负担是由virtual引起的,包括:

virtual function机制——用以支持一个有效率的“执行期绑定”(runtime binding);

virtual base class——用以实现“多次出现在继承体系中的base class,有一个单一而被共享的实体”。

此外,还有一些多重继承下的额外负担,发生在“一个derived class和其第二或后继base class的转换”之间。

C++对象模型(The C++ Object Model)

在C++中, 有两种class data members: static 和 nonstatic;
以及三种class member functions: static、nonstaitc 和 virtual。

已知有以下 class Point 声明:

class Point  
{  
public:  
    Point( float xval ); 
    virtual ~Point();

    float x() const;  
    static int PointCount();

protected:  
    virtual ostream&  print( ostream &os ) const;

    float _x;
    static int _point_count;  
};

这个class在机器中将会被如何表现呢?

这里写图片描述

  1. Nonstatic data members 被配置于每一个 class object 之内;

  2. Static data members 被存放在所有的 class object 之外;

  3. Static 和 nonstatic function members 也被存放在所有的 class object 之外;

  4. Virtual functions 则以两个步骤支持之:

    1)每一个 class 产生出一堆指向 virtual functions 的指针,放在表格之中,这个表格被称为virtual table(vtbl);

    2)每一个 class object 被添加了一个指针,指向相关的 virtual table,通常该指针被称为vptr。vptr的设定和重置都由每一个 class 的 constructor、destructor 和 copy assignment 运算符自动完成。每一个class所关联的 type_info object (用以支持 runtime type identification,RTTI)也经由 virutal table 被指出来,通常是放在表格的第一个slot处。

一个 class object 的内存大小

一般而言,要有:
1. 其 nonstatic data members 的大小总和;
2. 加上由内存对齐而填补的内存大小;(关于补齐,在《深入理解计算机系统》一书中有所描述)
3. 加上为了支持virtual而由内部产生的任何额外负担。

一个指针,不管它指向哪一种数据类型,指针本身的内存大小是固定的。

但是,一个指向类Test的指针是如何与一个指向整数的指针有所不同呢?
——从内存需求的角度来看,并没有什么不同,它们都需要足够的内存来存放一个机器地址
它们的不同之处在于,其寻址处理的object类型不同,也就是说,“指针类型”会教导编译器如何解释某个特定地址中的内存内容及其大小。
对于 void* 指针,由于它没有特定的类型,所以编译器并不知道如何去解释,这就是为什么一个类型为 void* 的指针只能够存放一个地址,但是不能够通过它操作所指之 object 的缘故。

对于转型(cast),它其实是一种编译器指令,大部分情况下并不改变一个指针所含的真正地址,它只影响“被指之物内存的大小和其内容”的解释方式。

加上多态之后

假设有一个基类ZooAnimal(16bytes),以及一个继承自ZooAnimal的类Bear(8bytes)。

Bear b("Yogi");
Bear *pb = &b;
Bear &rb = *pb;

b、pb、rb的内存需求:

不管是pointer还是reference(事实上由指针来实现的)都只需要一个word的空间(32位机器上是4bytes)。Bear object需要24bytes,包括ZooAnimal的16bytes和Bear所带来的8bytes。

假设我们的Bear object 放在地址1000处,一个Bear指针和一个ZooAnimal指针有什么不同?

Bear b;
ZooAnimal *pz = &b;
Bear *pb = &b;

它们都指向Bear object的第一个byte,差别是,pb所涵盖的地址范围是整个Bear object,而pz所涵盖的地址只包含Bear object中的ZooAnimal成分。

除了ZooAnimal成分中出现的members,你不能够使用pz来直接处理Bear的任何members。唯一例外是通过virtual机制。

一个pointer或一个reference之所以支持多态,是因为它们并不引发内存中任何与类型有关的内存委托操作,会受到影响的只是它们所指向的内存的“大小和内容解释方式”而已。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值