一、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. 前端(七)—— 盒模型之display、overflow、隐藏、border、margin、样式支持,层级结构

    display.overflow.隐藏.border.margin.样式支持,层级结构 一.盒模型之display 1.三种样式 block 块 inline 内联/行内 inline-block 内 ...

  2. 【三】Jmeter接口自动化测试系列之Http接口自动化实战

    作者:大虫 本文介绍 Jmeter 工具的 http 接口 自动化测试 实战! 为了通用性,就拿知乎 网站作为实战例子吧! 必备技能:http接口基础知识.抓包,本文不做详细介绍,不会的可以先百度恶补 ...

  3. 高并发下的缓存架构设计演进及redis常见的缓存应用异象解决方案

    待总结 缓存穿透 缓存击穿 缓存雪崩等

  4. 行动带来力量,周三(5月7日)晚IT讲座通知

    讲座简单介绍     ITAEM团队负责人骆宏等和大家周三晚8点(5月7日)相约钟海楼03035.和大家分享团队成员的"编程入门之路",在这里,同龄人(大三)以学生的角度.和大家分 ...

  5. 从零开始搭建系统2.1——Nexus安装及配置

    在安装配置Nexus时,请先确定您已经配置好jdk 1.创建目录 2.下载安装包 [root@localhost usr]# cd nexus 下载地址:https://www.sonatype.co ...

  6. Peasy.NET学习之并发问题处理

    Peasy.net之并发处理 BusinessServiceBase是ServiceBase的自定义实现,提供了额外的独特功能 首先,创建一个业务服务,该业务服务必须继承BusinessService ...

  7. 现如今,最热门的13个Java微服务框架

    曾经的 服务器领域 有许多不同的芯片架构???有哪些芯片架构???和操作系统???,经过长期发展,Java的“一次编译,到处运行”使得它在服务器领域找到一席之地,成为程序员们的最爱. 本文,我们将和大 ...

  8. 再学 GDI+文本输出文本样式

    代码文件: unit Unit1; interfaceuses   Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls ...

  9. JavaScript闭包和回调详解

    一.闭包 闭包(closure)是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现. 闭包有三个特性: 1.函数嵌套函数; 2.函数内部可以引用外部的参数和变量; 3.参 ...

  10. ASP.NET MVC Controller激活系统详解2

    一.引言 此篇博文紧接上篇博文进行阐述,本篇博文阐述的主题是Controller激活和url路由 二.总述 ASP.NET路由系统是HTTP请求抵达服务端的第一道屏障,它根据注册的路由规则对拦截的请求 ...