一、C和C++对比:

C语言的Point3d: 数据成员定义在结构体之内,存在一组各个以功能为导向的函数中,共同处理外部的数据。

 typedef struct point3d
{
float x;
float y;
float z; }Point3d;

Point3d可能采用独立的“抽象数据类型”(abstract data type)来实现:  

 class Point3d
{
public:
Point3d(float x = 0.0,float y = 0.0,float z = 0.0)
:_x(x), _y(y), _z(z) {} float x() {return _x;}
float y() {return _y;}
float z() {return _z;} void x(float xval) {_x = xval;}
private:
float _x;
float _y;
float _z;
} inline ostream&
operator<<(ostream &os,const Point3d &pt)
{
os << pt.x()<<pt.y()<<pt.z();
}

、加上封装之后的布局成本:

  加上封装之后,布局成本增加了多少?    并没有增加布局成本。一般而言,并没有什么理由说C++程序一定比C庞大和迟缓。

  因为三个数据成员直接内含在每一个类对象中,而成员函数虽然含在class的声明之内,但是却不出现在对象中。每一个非内联成员函数只会诞生一个函数实例。至于“拥有零个或一个定义”的内联函数则会在每一个模块身上产生一个函数实例。

虽然C++的类含有封装特新,但是并没有给系统在占用空间和执行上带来不良后果。

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

  • virtual function(虚函数)   用以支持一个有效率的“执行器绑定(runtime binding)”
  • virtual base class (虚基类)  用以实现“多次出现在继承体系中的 base class(基类),有一个单一而被共享的实例。”

还有一些其他的额外负担,比如一个派生类和它的第二或后继承的基类之间的转换。


三、C++对象模型:

  在C++中,有两种类数据成员:static  nonstatic;  三种类成员函数:static  nonstatic  virtual

例如下面这个class在机器中是怎么分布的呢,即如何modeling出各种数据成员和成员函数:

 class Point {
public:
Point(float xval) ;
virtual ~Point(); float x() const;
static int PointCount(); ptotected:
virtual ostream&
print(ostream &os )const ;
float _x;
static int _point_count;
};

分别有以下几个模型:

  • 简单对象模型

     每一个对象有是一系列的槽,每一个槽指向一个成员。成员按其声明排序。每一个数据成员或成员函数都有自己的一个槽。如下图所示:

在这种情况下,放在对象中的是指向成员的指针,这样可以避免成员有不同的类型,因而需要不同存储空间的问题。对象中的成员是以槽的索引值来寻址的。上图中_x的索引值是6._point_count的索引值是7。一个类对象的大小 = 指针大小 * 类中声明的成员个数。

  • 表格驱动模型

    表格对象模型是把所有与members相关的信息抽出来,放在一个数据成员表格和一个成员函数表格中,类对象本身只含有指向这两个表格的指针。成员函数表格是一系列的槽,每个槽指向一个成员函数。数据成员表格则直接包含数据成员本身。如下图所示:

虽然这个模型没有实际应用到C++编译器上,但是成员函数表格这个概念却成为支持虚函数的一个有效方法。

  • C++对象模型

    C++对象模型是从简单对象模型派生而来,并对内存空间和存取时间做了优化。在C++对象模型中,非静态数据成员被配置在每一个类对象中,静态数据成员被配置在类对象之外。静态和非静态成员函数也被放在类对象之外。虚函数的配置方式如下说明:

  1. 每个类产生一堆指向虚函数的指针,放在虚函数表中(virtual table,vtbl)
  2. 每个类对象中含有一个指向虚函数表的指针vptr。vptr的设定(setting)和重置(resetting)都由每个类的构造函数、析构函数、拷贝赋值函数自动完成。每个类关联的type_info 对象(用来支持 runtime type identification,RTTI)也由虚函数表指出来,通常放在虚函数表的第一个槽。

C++对象模型的优点是它的空间和时间效率高,缺点是类对象的非静态数据成员被修改(增加、移除等),那么程序就需要重新编译。相比前述的表格驱动模型就多了一层间接性,不过也付出了空间和执行效率上的耗费。


 四、在C++对象模型上加上继承(Inheritance)

  • 单一继承
 class Library_materials {....};
class Book : public Library_materials {...};
class Rental_book : public Book {...};
  • 多重继承
 class iostream:
public istream,
public ostream {...};
  • 虚拟继承
class istream : virtual public ios{...};
class ostream : virtual public ios {...};

在虚继承情况下,不管基类在继承串中派生(derived)多少次,都只有一个实例(subobject)。例如iostream中,只有virtual ios base class一个实例。

一个派生类如何模塑其基类的实例呢?

  • 在简单对象模型中:

    派生类对象中有一个槽指向基类,槽内含有基类实例(base class subobject)的地址。这种方法的主要缺点是因为间接性会导致空间和存取时间上的额外负担,优点是改变基类不会影响类对象的大小。

  • 在表格模型中:

每个类对象中内涵一个bptr,它会被初始化指向其基类表(base class table),和虚函数表中含有虚函数地址一样,在基类表格(base class table)中,每个槽内有一个相关的基类地址,。这种方法的缺点是:由于间接性导致空间和存取时间的额外负担;优点是:每个类对象中对于继承都有一致的表现:每个类对象都会在某个固定位置上放置一个基表格指针,与基类的大小或个数无关。第二个有点是:无序改变类对象的大小,就可以放大、缩小,或更改基类表格。

下图是基类表格在虚继承中的应用:

  

不管上述哪一种体制,“间接性”的级数都因为继承的深度而增加。例如Rental_book需要两次间接存取才能够探取到继承自Library_materials的成员,而Book只需要一次。如果在派生类内复制一个指针,指向继承串链中的每一个基类,倒是可以获得一个永远不变的存取时间,当然这也需要额外的空间来放置额外的指针。

C++最初采用的继承模型并不运用任何间接性,基类实例的数据成员被直接放置于派生类对象中,这种方法虽然可以很方便且最有效率的对基类成员存取。但缺点是基类成员有任何改变,所有用到该基类的派生类对象都必须重新编译。

从C++2.0起开始导入虚基类(virtual base class),虚基类的原始模型是在类对象中为每一个有关联的虚基类加上一个指针指向这些虚基类。其他派生的模型不是导入一个虚基类表格(Virtual base class table)就是扩充原有的虚表格(virtual table),以便维护每一个虚基类的位置。


五、对象模型如何影响程序:

  不同的对象模型,会导致两个结果:现有程序代码必须修改或者必须加入新的程序代码。

 X foobar()
{
X xx;
X *px = new X; // foo是一个虚函数
xx.foo();
px->foo(); delete px;
return xx;
}

上面这个类X定义了一个拷贝构造函数、虚析构函数、和一个虚函数foo,则这个函数有可能在内部转换为:

 void foobar(X &_result)
{
//构造_result
//_result 用来取代localxx
_result.X::X(); //扩展X *px = new X; new在自由存储区开辟了一块内存,px是位于栈内存中
px = _new(sizeof(X)); //px指向的对象开辟一块新内存
if(px != )
px->X::X(); //执行拷贝构造 //扩展xx.fo() 但是不适用virtual机制
//以_result 取代xx
foo(&_result); //使用virtual机制扩展px->fo()
(*px->vtbl[]) (px) //X.foo() //扩展delete px;
(*px ->vtbl[](px)); //析构函数
//无需使用named return statement
//无须摧毁local object xx
}

上述代码的理解如下所示:

深度探索C++对象模型之第一章:关于对象之C++对象模型的更多相关文章

  1. 《深度探索C++对象模型》第一章 | 关于对象

    C++对象模式 非静态数据成员放置在每个类对象内,静态数据成员则被放置在所有类对象之外.静态和非静态的成员函数也被放置在所有类对象之外.每个类产生一堆指向虚函数的指针,放在虚表(vtbl)中.每个类对 ...

  2. 【C++对象模型】第一章 关于对象

    1.C/C++区别 C++较之C的最大区别,无疑在于面向对象,C程序中程序性地使用全局数据.而C++采用ADT(abstract data tpye)或class hierarchy的数据封装.类相较 ...

  3. 深度探索C++对象模型之第一章:关于对象之对象的差异

    一.三种程序设计范式: C++程序设计模型支持三种程序设计范式(programming paradiams). 程序模型(procedural model) char boy[] = "cc ...

  4. 深度探索C++对象模型之第一章:关于对象之关键词所引起的差异

    ————如果不是为了努力维护与C之间的兼容性,C++远比现在简单的多. 如果一个程序员渴望学习C++,但是他却发现书中没有熟悉的struct,一定会苦恼,将这个主题包含到C++里,可以提供语言转移时的 ...

  5. Android深度探索-卷1第六章心得体会

    这章主要介绍了第一个linux驱动程序:统计单词个数.Linux系统将每一个驱动都映射成一个文件,这些文件称为设备文件或驱动文件,都保存在/dev目录中.大多数Linux驱动都有与其对应的设备文件,因 ...

  6. Android深度探索-卷1第七章心得体会

    创建LED驱动的设备文件 第一步:使用cdev_init函数初始化cdev 第二步:指定设备号.直接在代码指定或动态分配 第三步:使用cdev_add函数将字符设备添加到内核中的字符设备数组中 第四步 ...

  7. Android深度探索-卷1第五章心得体会

    S3C6410是由三星公司推出的一款低功耗.高性价比的RISC处理器,开发是,首先安装minicom串口调试工具: 第一步:检测当前系统是否支持USB转串口. Lsmod | grep usseria ...

  8. Android深度探索-卷1第四章心得体会

    这一章的和三章的git用法有联系,so,吧上一章的git基本用法搞好了再来,具体的方法就是看书上网查,这里就不做详细步骤介绍了.这章就有点意思了,是源码的下载和编译,有能看的,能自己鼓捣的,本章介绍的 ...

  9. Android深度探索-卷1第三章心得体会

    第三章整章介绍了git,git是一个开源的分布式版本控制系统,用以有效.高速的处理从很小到非常大的项目版本管理.通过配置git后可以很方便的找到需要的资源,更多的是代码和包,可以在本地建立版本库,为了 ...

随机推荐

  1. Codeforce 1182B Plus from Picture

    题目链接:http://codeforces.com/problemset/problem/1182/B 题意:检查图中 * 形成的是否是唯一的十字. 思路:dfs找到十字的中心,反向消除十字,最后检 ...

  2. mysql优化1:建表原则

    建表三大原则: 定长和变长分离 常用字段和不常用字段分离 使用冗余字段或冗余表 1.定长与变长分离 如 id int,占4个字节,char(4)占4个字符长度,也是定长,time 即每一个单元值占的字 ...

  3. 用注解实现SpringMvc

    在第一次完成spirngmvc代码的基础上: 开始时代码 index.jsp <%@ page contentType="text/html;charset=UTF-8" l ...

  4. Lung Nodule Detection------work log

    有时候真的不知道自己是怎么走上,模式识别,人工智能的这条路上的.但既然走上了这条路,我就没有理由荒废我所学到的东西.在学校里面研究了很长的时间的肺结节检测,但那都是只限于研究和写论文,现在我想把大家的 ...

  5. JUC源码分析-集合篇:并发类容器介绍

    JUC源码分析-集合篇:并发类容器介绍 同步类容器是 线程安全 的,如 Vector.HashTable 等容器的同步功能都是由 Collections.synchronizedMap 等工厂方法去创 ...

  6. CSS3:FlexBox的详解

    Flexbox是Flexible box 的简称(灵活的盒子容器),是CSS3引入的新的布局模式.它决定了元素如何在页面上排列,使它们能在不同的屏幕尺寸和设备下可预测地展现出来. 它之所以被称为 Fl ...

  7. 商城sku的选择功能--客户端

    前段时间,刚好做到了有关sku这个功能.客户端的sku,和后台管理系统的sku.当初查了大量资料,遂做个记录,以免忘记. 这篇先写客户端的sku功能把,类似于去淘宝京东等购物,就会有个规格让你选择.如 ...

  8. Mysql ibd恢复(delete 数据)

    转载:https://www.linuxidc.com/Linux/2017-05/143870.htm 首先呢,请各位注意Percona Data Recovery Tool for InnoDB工 ...

  9. PHP - 实现 strStr()

    实现 strStr() 函数. 给定一个 haystack 字符串和一个 needle 字符串,在 haystack 字符串中找出 needle 字符串出现的第一个位置 (从0开始).如果不存在,则返 ...

  10. Aria2 Centos8 安装配置

    使用chkconfig 或者 chkconfig –list就可以看出当前系统已经设置的各个服务在各个运行级别下的开闭状态.如果我们想设置某个服务自启动或者关闭的话,那么只需要按照下面的格式使用即可 ...