首页 技术 正文
技术 2022年11月23日
0 收藏 885 点赞 3,647 浏览 2416 个字

再读《深入探索C++对象模型》笔记。

关于对象

C++在加入封装后(只含有数据成员和普通成员函数)的布局成本增加了多少?

  • 答案是并没有增加布局成本。就像C struct一样,memeber functions虽然含在class的声明之内,却不出现在object中。每一个non-inline member function只会诞生一个函数实体。至于每一个“拥有零个或一个定义的” inline function则会在其每一个使用者(模块)身上产生一个函数实体。

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

  • virtual funciton机制,用以支持一个有效率的“执行期绑定”(runtime binding)
  • virtual base class,用以实现“多次出现在继承体系中的base class,有一个单一而被共享的实体”

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

在C++中,有两种class data members:static 和 nonstatic,以及三种class member functions:static、nonstatic和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;
};

C++对象模型中,nonstatic data members被配置于每一个class object之内,static data members则被存放在所有的class object之外。static和nonstatic function members也被放在所有的class object之外。virtual function则以两个步骤支持之:

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)也经由virtual table被指出来,通常放在表格的第一个slot处

故上面的声明所对应的对象模型如下:

上图说明了C++对象模型如何应用于Point Class身上,这个模型的主要优点在于它的空间和存取时间的效率。主要缺点是:如果应用程序代码未曾改变,但所用到的class objects的nonstatic data members有所修改(有可能是增加、移除或更改),那么应用程序代码同样得重新编译。

继承关系可以指定为虚拟(virtual,也就是共享的意思):在虚拟继承的情况下,base class不管在继承链中被派生(derived)多少次,永远只会存在一个实例(称为subobject)。

class istream : virtual public ios{ ... };
class ostream : virtual public ios{ ... };

对象的差异

C++以下列方法支持多态:

  • 经由一组隐式的转化操作。例如把一个derived class指针转化为一个指向其public base type的指针
  • 经由virtual function机制
  • 经由dynamic_cast和typeid运算符

多态的主要用途是经由一个共同的接口来影响类型的封装,这个接口通常被定义在一个抽象的base class中。这个共享接口是以virtual function机制引发的,它可以在执行期根据object的真正类型解析出到底是哪一个函数实体被调用。

需要多少内存才能表现一个class object?

  • 其nonstatic data members的总和大小
  • 加上任何由于aliginment的需求而填补上去的空间(可能存在于members之间,也可能存在于集合体边界)
  • 加上为了支持virtual而由内部产生的任何额外负担

一个指针(引用),不管它指向哪一种数据结构,指针本身所需的内存大小是固定的。

举例如下:一个指向ZooAnimal的指针是如何地与一个指向整数得指针或一个指向template Array的指针有所不同的呢?

ZooAnimal *px;
int *pi;
Array<string> *pta;

以内存需求的观点来说,没有什么不同!它们三个都需要足够的内存来放置一个机器地址(通常是个word)。“指向不同类型的各指针”间的差异,既不在其指针表示法不同,也不在其内容(代表一个地址)不同,而是在其所寻址出来的object类型不同,也就是说,“指针类型”会教导编译器如何解释某个特定地址中的内存内容及其大小。

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

当一个base class object被直接初始化为(或被指定为)一个derived class object时,derived object就会被切割(sliced)以塞入较小的base type内存中,derived type将没有留下任何蛛丝马迹。多态于是不再呈现,而一个严格的编译器可以在编译器解析一个“通过此object而触发的virtual function调用操作”,因而回避virtual机制。如果virtual function被定义为inline,则更有效率上的大收获。

微信扫一扫

支付宝扫一扫

本文网址:https://www.zhankr.net/141365.html

相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:875 阅读:5,090
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:806 阅读:3,508
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:565 阅读:4,320
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:730 阅读:4,314
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:4,920
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:3,105
发表评论
暂无评论

还没有评论呢,快来抢沙发~

助力内容变现

将您的收入提升到一个新的水平

点击联系客服

在线时间:8:00-16:00

客服电话

400-888-8888

客服邮箱

ceotheme@ceo.com

扫描二维码

关注微信公众号

扫描二维码

手机访问本站