什么是C++模型.docx
《什么是C++模型.docx》由会员分享,可在线阅读,更多相关《什么是C++模型.docx(25页珍藏版)》请在冰豆网上搜索。
什么是C++模型
1、什么是C++对象模型
1、语言中直接支持面向对象程序设计的部分
2、各种支持的底层实现机制
二、C语言是面向进程的:
语言本身没有支持数据和函数之间的关联性,是程序性的,分布在各个以功能函数为导向的函数中
他们处理的是共同的外部数据。
C++用独立的“抽象数据类型”ADT实现
3、C++在布局和存取时刻上主要额外负担的VIRUTAL引发的
1、virtualfunction机制
2、virtualbaseclass多次继承系统中的基类,有一个单一而被共享的实体
4、C++有两种类成员数据类型[classdatatype]:
static,nonstatic
有三种类成员函数类型[classmemberfunction]:
static,nonstatic,virtual
五、C++对象模型
nonstaticdatamember非静态数据成员被置于类对象中
staticdatamember静态成员函数被置放在所有类对象之外[被放置在程序中的datasegment中]
staticfunction和nonstaticfunction也放在类对象之外
staticfunction在我看来类似于nonmemberfunction
virtualfunction
1、每一个类产生一对指向virtualfunction的指针,放置在表格中virtualtable(vtbl)
2、类对象添加了一个指针,指向vtbl,为vptr
六、在虚拟继承情形下,baseclass无论在继承串联中被派生过量少次,永久只存在一个实体subobject
7、关键词struct和class的不同:
struct体现了数据萃取的概念
class体现了adt(abstractdatatype)概念
我看来只要是思想上的差异,没有其他的差别
八、C++程序设计模型直接支持三种“程序设计典范”,也就是不只是OO了
1、程序模型:
面向过程的设计
2、抽象数据类型模型:
我看来解释数据萃取型STRUCT
3、面向对象模型
九、一个指针,无论它指向哪个数据类型,指针本身需要的内存大小是固定的,指向不同类型之各指针之间
的差异,即不在其指针表示法的不同,也不在其内容的不同,而在于它寻址出来的OBJECT类型的不同,我
看来指针的类型就是为了通知编译器,让编译器的有不同的处理方式
10、多态就是指利用虚函数吗?
1一、当一个基类被直接初始化(或被指定为)一个继承类时,继承类就会被切割,以塞进较小的基类内存中
1二、一个类若是没有自概念的构造函数,编译器会生成一个却省的构造函数,可是那个构造函数是没有具体作用的
被合成的构造函数,只满足编译器的需要,而不是满足程序的需要
合成的构造函数只对基类对象和类对象成员函数的初始化,不对其他非静态DATAMEMBER初始化
不是任何没有却省构造函数的类都会被合成出一个却生构造函数
13、内联函数有静态连接,不会被档案之外者看到,若是内联函数很复杂,不适合做成内联函数,编译器会
合成一个明确的、非内联的函数实体
14、若是一个类含有一个或一个以上的类对象成员函数,类的构造函数会挪用每一个类对象的却生构造函数
1五、拷贝构造函数是类的一个参数是其类名的构造函数,若是类顶用户没有明确概念,内部是以所谓的DEFAULT
memberwiseinitialization,即却省的对每个成员函数初始化手法完成
根据bit来拷贝构造函数
1六、坚持所有的member的初始化操作在memberinitializationlist中完成,初始化顺序不是依照initialization
中的顺序完成,是按照类中成员定义的顺序完成,编译器编译时将initialization放置在构造函数用户自定的编码前
17、一个空类大小不是为空的,有一个隐讳的1字节,那时编译器安插进取的一个char,使得那个类在内存中分派
独一无二的地址。
[我不知道是否所有的编辑器都是如此?
]
1八、类的大小跟机械和编辑器有关,受到三种因素的印象
1、语言本身所造成的额外负担
2、编译器对特殊情况进行的优化处理
3、alignment的限制,alignment就是将某数的整倍数,例如32位计算机上,一般为4字节
19、不管类产生多少个对象,静态数据成员永远只存在一份实体
掀起你的盖头来——谈VC++对象模型
2006-02-1713:
59作者:
程化编译出处:
blog责任编辑:
一个C++员,想要进一步提升技术水平的话,应该多了解一些语言的语意细节。
对于利用VC++的程序员来讲,还应该了解一些VC++对于C++的诠释。
InsidetheC++ObjectModel虽然是一本好书,但是,书的篇幅多一些,又和具体的VC++关系小一些。
因此,从篇幅和内容来看,译者以为本文是深切理解C++对象模型比较好的一个起点。
这篇文章以前看到时就觉得很好,旧文重读,感觉理解得更多一些了,于是产生了翻译出来,与大家共享的想法。
虽然文章不长,但时间有限,又若干次在翻译时打盹睡着,拖拖拉拉用了小一个月。
一方面因本人水平所限,另一方面因翻译时经常打盹,错误之处恐怕不少,欢迎大家批评指正。
前言
了解你所利用的编程语言究竟是如何实现的,对于C++程序员可能特别成心义。
第一,它能够去除咱们对于所利用语言的神秘感,使咱们不至于对于编译器干的活感到完全难以想象;尤其重要的是,它使咱们在Debug和利用语言高级特性的时候,有更多的把握。
当需要提高代码效率的时候,这些知识也能够专门好地帮忙咱们。
本文着重回答这样一些问题:
*类如何布局?
*成员变量如何访问?
*成员函数如何访问?
*所谓的“调整块”(adjusterthunk)是怎么回事?
*使用如下机制时,开销如何:
*单继承、多重继承、虚继承
*虚函数调用
*强制转换到基类,或者强制转换到虚基类
*异常处理
首先,我们顺次考察C兼容的结构(struct)的布局,单继承,多重继承,以及虚继承;接着,我们讲成员变量和成员函数的访问,当然,这里面包含虚函数的情况;再接下来,我们考察构造函数,析构函数,以及特殊的赋值操作符成员函数是如何工作的,数组是如何动态构造和销毁的;最后,简单地介绍对异常处理的支持。
对每个语言特性,我们将简要介绍该特性背后的动机,该特性自身的语意(当然,本文决不是“C++入门”,大家对此要有充分认识),以及该特性在的VC++中是如何实现的。
这里要注意区分抽象的C++语言语意与其特定实现。
微软之外的其他C++厂商可能提供一个完全不同的实现,我们偶尔也会将VC++的实现与其他实现进行比较。
类布局
本节讨论不同的继承方式造成的不同内存布局。
1、C结构(struct)
由于C++基于C,所以C++也“基本上”兼容C。
特别地,C++规范在“结构”上使用了和C相同的,简单的内存布局原则:
成员变量按其被声明的顺序排列,按具体实现所规定的对齐原则在内存地址上对齐。
所有的C/C++厂商都保证他们的C/C++编译器对于有效的C结构采用完全相同的布局。
这里,A是一个简单的C结构,其成员布局和对齐方式都一目了然。
structA{
charc;
inti;
};
译者注:
从上图可见,A在内存中占有8个字节,依照声明成员的顺序,前4个字节包括一个字符(实际占用1个字节,3个字节空着,补对齐),后4个字节包括一个整数。
A的指针就指向字符开始字节处。
二、有C++特征的C结构
当然了,C++不是复杂的C,C++本质上是面向对象的语言:
包含继承、封装,以及多态。
原始的C结构经过改造,成了面向对象世界的基石——类。
除了成员变量外,C++类还可以封装成员函数和其他东西。
然而,有趣的是,除非为了实现虚函数和虚继承引入的隐藏成员变量外,C++类实例的大小完全取决于一个类及其基类的成员变量!
成员函数基本上不影响类实例的大小。
这里提供的B是一个C结构,然而,该结构有一些C++特征:
控制成员可见性的“public/protected/private”关键字、成员函数、静态成员,以及嵌套的类型声明。
虽然看着琳琅满目,实际上只有成员变量才占用类实例的空间。
要注意的是,C++标准委员会不限制由“public/protected/private”关键字分开的各段在实现时的先后顺序,因此,不同的编译器实现的内存布局可能并不相同。
(在VC++中,成员变量总是按照声明时的顺序排列)。
structB{
public:
intbm1;
protected:
intbm2;
private:
intbm3;
staticintbsm;
voidbf();
staticvoidbsf();
typedefvoid*bpv;
structN{};
};
译者注:
B中,为何staticintbsm不占用内存空间?
因为它是静态成员,该数据寄存在程序的数据段中,不在类实例中。
3、单继承
C++提供继承的目的是在不同的类型之间提取共性。
比如,科学家对物种进行分类,从而有种、属、纲等说法。
有了这种层次结构,我们才可能将某些具备特定性质的东西归入到最合适的分类层次上,如“怀孩子的是哺乳动物”。
由于这些属性可以被子类继承,所以,我们只要知道“鲸鱼、人”是哺乳动物,就可以方便地指出“鲸鱼、人都可以怀孩子”。
那些特例,如鸭嘴兽(生蛋的哺乳动物),则要求我们对缺省的属性或行为进行覆盖。
C++中的继承语法很简单,在子类后加上“:
base”就可以了。
下面的D继承自基类C。
structC{
intc1;
voidcf();
};
structD:
C{
intd1;
voiddf();
};
既然派生类要保留基类的所有属性和行为,自然地,每一个派生类的实例都包括了一份完整的基类实例数据。
在D中,并非是说基类C的数据必然要放在D的数据之前,只不过如此放的话,能够保证D中的C对象地址,恰好是D对象地址的第一个字节。
这种安排之下,有了派生类D的指针,要取得基类C的指针,就没必要要计算偏移量了。
几乎所有知名的C++厂商都采用这种内存安排。
在单继承类层次下,每一个新的派生类都简单地把自己的成员变量添加到基类的成员变量以后。
看看上图,C对象指针和D对象指针指向同一地址。
4、多重继承
大多数情况下,其实单继承就足够了。
但是,C++为了我们的方便,还提供了多重继承。
比如,我们有一个组织模型,其中有经理类(分任务),工人类(干活)。
那么,对于一线经理类,即既要从上级经理那里领取任务干活,又要向下级工人分任务的角色来说,如何在类层次中表达呢?
单继承在此就有点力不胜任。
我们可以安排经理类先继承工人类,一线经理类再继承经理类,但这种层次结构错误地让经理类继承了工人类的属性和行为。
反之亦然。
当然,一线经理类也可以仅仅从一个类(经理类或工人类)继承,或者一个都不继承,重新声明一个或两个接口,但这样的实现弊处太多:
多态不可能了;未能重用现有的接口;最严重的是,当接口变化时,必须多处维