读书笔记《深入探索C++对象模式》

第一章:关于对象

P6:C++的布局以及存取时间上主要的额外负担是由virtual引起的,包括virtual function机制以及virtual base class

1.1 C++对象模式

P6:2种数据成员类型:nonstatic和static,三种成员函数类型:static,nonstatic和virtual
P7:简单对象模型:members按照声明顺序,各被指定一个slot,只存放指向member的指针
P8:表格驱动模型:object保存指向两个表格的指针,一个data member table,一个member function member
P9:c++对象模型:nonstatic data member放在每个object之内,static data member放在个别的object之外。static和nonstatic function member也放在个别的object之外。对于virtual function,1:每个class产生一堆指向virtual function的指针,放在表格之中,即virtual table(vtbl)。2:每个object安插一个指针指向相关的virtual table,成为vptr。vptr通常放在第一个slot.
P11:在虚拟继承的情况下,base class不管在继承串链中被派生多少次,永远只会存在一个实例。
P14:VTBL的第一项是type_info for object

1.2 关键词所带来的差异

1.3 对象的差异

P27:一个class object所需内存空间:1:其nonstatic data member的总和大小。2:加上任何由于alignment的需求而填补上去的空间。3:加上为了支持virtual而由内部产生的任何额外负担。
P31:
Bear b;
ZooAnimal *pz=&b;
Bear *pb=&b;
//ZooAnimal 为Bear父类。
//pb所涵盖的地址包含整个bear object,而pz所涵盖的地址只包含Bear object中的ZooAnimal subobject。除了ZooAnimal subobject中出现的members,不能使用pz来直接处理Bear的任何members,唯一的例外是通过virtual机制

P32:类型的信息的封装并不是维护于pz之中,而是维护于link之中,此link存在于object的vptr和vptr所指的virtual table之中。

第二章:构造函数语义学

2.1 Default Constructor 的构造操作

P41:如果一个class没有任何constructor,但它内含一个member object,而后者有constructor,那么这个class的implicit default constructor就是nontrivial。那么编译器就要为class合成一个default constructor。
P41:一个inline函数有静态链接。
P42:被合成default constructor只满足编译器的需要,而不是程序的需要。
P42:若class A内含一个或者一个以上的member class objects,那么A的每一个constructor必须调用每一个member class的default constructor,否则编译器会扩展已存在的constructor,在其中安插一些代码。以member 声明顺序安插程序代码。
P44:如果一个没有constructor的class派生自一个带有default constructor的base class,那么派生类的default constructor会被视为nontrivial,并因此需要被合成。
P44:下面情况也要合成default constructor:1:class声明或继承一个virtual function2:class派生自一个继承串链,其中有一个或更多的virtual base classes。对于此种情况,会有2个扩张行动在编译期间发生:1:一个virtual function table会被编译器产生出来,内放class的virtual functions地址。2:在每个class object中,一个额外的vptr会被编译器合成出来,内含相关class vtbl地址。
P47:在合成的default constructor中,只有base class subobjects和member class objects会被初始化
P47:两个误解(下面两个都是错误的):1:任何class如果没有定义default constructor,就会被合成出一个。2:编译器合成后出来default constructor会显示设定class内每一个data member的默认值。

2.2 Copy Constructor的构造操作

P51:同样,copy constructor区分为trivial和nontrivial,只有nontrivial的实例才会被合成于程序之中。决定是否为trivial的标准在于class是否展现出所谓的bitwise copy semantics。不展现出bitwise copy semantics时才会有编译器生产出来。
P53:什么时候一个class不展现出bitwise copy semantics:1:当class内含一个member object而后者的class声明有一个copy constructor(不论是显示的还是编译器合成的)。2:当class继承一个base class而后者存在一个copy constructor(不论是显示的还是编译器合成的)。3:当class声明一个或多个virtual functions时。4:当class派生自一个继承串链,其中有一个或者多个virtual base classes。
前两种情况,编译器必须将member或者base class的copy constructor调用操作安插到被合成的copy constructor。
P54:当编译器导入一个vptr到class之中时,该class就不展现出bitwise semantics。

2.3 程序转换语义

P61:必要的程序转换有2个阶段:1:重写每一个定义,其中的初始化操作会被剥除。2:class的copy constructor调用操作会被安插进去。

2.4 成员的初始化队伍

P75:下列情况为了让程序能够顺利编译,必须使用member initialization list:1:当初始化一个reference member时。2:当初始化一个const member时。3:当带哦用一个base class的constructor,而它带有一组参数时。4:当调用一个member class的constructor,而它带有一组参数时。
P77:List中的项目顺序是有class中member声明顺序决定的,不是由list中的排列顺序决定。
P79:initialization list的项目被放在用户代码之前。

第三章:DATA语义学

P84:对于空类,有一个隐藏的1byte大小,那是被编译器安插进去的一个char,这使得这个class的两个objects得以在内存中配置独一无二的地址;
P87:一个virtual base class subobject只会在derived class中存在一份实例,不管它在继承体系中出现了多少次。

3.1 Data Member的绑定

3.2 Data Member的布局

3.3 Data Member的存取

P95:每一个static data member只有一个实例,存放在程序的data segment之中。
P96:若取一个static data member的地址,会得到一个指向其数据类型的指针,而不是一个指向其class member的指针。对于static data member,点运算符和->效果一样。
P98:指向data member的指针,其offset值总是被加上1,这样用来区分出“一个指向data member的指针,用以指出class的第一个member”和“一个指向data member的指针,没有指出任何member”。
P99:由于多态的性质,->的类型要到执行期才能确定,会多一个额外的简介导引。而点操作符不会,因为类型就是该类型,不管它是否继承自virtual base class,member的offset位置在编译器就固定了。

3.4 继承与data member

P99:在大部分编译器上头,base class members总是先出现,但属于virtual base class的除外。
P100:一般而言,具体继承并不会增加空间或者存取时间上的额外负担。
P108:virtual table的元素个数一般而言是被声明的virtual function个数,再加上一个或者2个slots(用以支持runtime type identification)
P117:class如果内含一个virtual base class subobjects,将被分割为两部分:一个不变区域和一个共享区域。不变区域总是拥有固定offset,这部分可以直接存取。而共享区域其位置会因为每次的派生操作而有变化,只能间接存取。

3.5 对象成员的效率

P128:程序员如果关心其程序效率,应该实际测试,不要光凭推论、常识判断或者假设。

3.6 指向data members的指针

P130:所有编译器不是把vptr放在对象的头,就是放在对象的尾。
P131:为了区分没有指向任何data member的指针和一个指向第一个data member的指针,当取data members的地址,传回的值总是多1.
P132:取一个nonstatic data member的地址,将会得到它在class中的offset。取一个绑定于真正class object身上的data member的地址,将会得到该member在内存中的真正地址

第四章:function语义学

4.1 member的各种调用方式

P141:nonstatic member function至少必须和一般的nonmember function有相同的效率。
P141:将member function改为nonmember function:1:安插this指针2:改为经由this指针存取3:重新写成一个外部函数。
P150:static member functions的主要特征是没有this指针,所以1:不能直接存取nonstatic members。2:不能声明为const,volatile或者virtual。3:不需要经由class object调用。

4.2 virtual member function

P163:thunk是一小段assembly代码:用来:1:以适当的offset值调整this指针。2:跳到virtual function里。

4.3 函数的效能

P171:inline函数不只能节省一般函数调用所带来的额外负担,也提供了程序优化的额外机会。编译器会将“被视为不变的表达式”提到循环之外。

4.4 指向member function的指针

P176:对于一个virtual member function取地址,只能获得一个virtual table中的索引值。
P181:一个指向member function的指针,是一个结构,含有3个字段:index,faddr,delta。index若不是内含一个相关virtual table的索引值,就是以-1表示函数是nonvirtual,faddr持有nonvirtual member function的地址。delta只有一个可能的this指针调整值。

4.5 inline functions

P188:inline函数中的局部变量,再加上有副作用的参数,可能会导致大量临时性对象的产生。特别是如果它以单一表达式被扩展多次的话。

第五章:构造、析构、拷贝语义学

5.1 无继承情况下的对象构造

P197:c和c++的一个差异在于,BSS data segment在c++中相对的不重要,c++的所有全局对象都被以初始化过的数据来对待。

5.2 继承体系下得对象构造

P211:在虚拟继承情况下,由最底层的class完成共享的基类的构造。

5.3 对象复制语意学

P220:一个class对于默认的copy assignment operator,在以下情况,不会表现出bitwise copy语意:1:单class内含一个member object,而其class 有一个copy assignment operator时。2:当一个class的base class有一个copy assignment operator时。3:单一个class生命了任何virtual functions(我们一定不要拷贝右端class object的vptr地址)。4:当class继承自一个virtual base class。
P222:copy assignment operator缺乏一个member assignment list(也就是平行于member initialization list的东西)

5.4 对象效能

5.5 析构语意学

P231:如果class没有定义destructor,那么只有在class内含的member object(亦或是class自己的base class)拥有destructor的情况下,编译器才会自动合成一个。否则,destructor被视为不需要,也就不会被合成。
P235:析构函数顺序:1:destructor的函数本体首先被执行。2:如果class拥有member class objects,而后者拥有destructors,那么它们会以其声明顺序的相反顺序被调用。3:如果object内含一个vptr,现在被重新设定,指向适当之base  class的virtual table。4:如果有任何直接的上一层nonvitrual base classes拥有destructor,它们会以其声明顺序的相反顺序被调用。5:如果有任何virtual base classes拥有destructor,而目前讨论的这个class是最尾端的class,那么它们会以其原来的构造顺序的相反顺序被调用。

第六章:执行期语意学

6.1 对象的构造和析构

P242:c++程序中所有的global objects都被放置在程序的data segment中,如果显示指定给它一个值,此object将以该值为初值,否则所分配到的内存内容为0。
P252:经由一个指针来启动constructor,将无法(不被允许)存取default argument values。

6.2 new 和 delete运算符

6.3 临时性对象

P271:临时对象的被摧毁,应该是对完整表达式求值过程中的最后一个步骤。该完整表达式造成临时对象的产生。
P274:凡持有表达式执行结果的临时性对象,应该存留到object的初始化操作完成为止
P275:如果一个临时性对象被绑定于一个reference,对象将残留,知道被初始化之reference的生命结束,或者直到临时对象的声明范畴结束---视哪一种情况先到达而定。

第七章:站在对象模型的顶端

7.1 Template

P280:template metaprograms技术:class expression templates将在编译时期而非执行期被评估,因为带来重大的效率提升。
P284:只有在member function被使用的时候,才会被实例化
P287:cfront对template的处理是完全解析但不做类型检查;只有在每一个实例化操作发生时才做类型检查。所以在一个parsing策略之下,所有词汇错误和解析错误都会在处理template声明的过程中被标示出来。
P290:Template之中,对于一个nonmember name的决议结果,是根据这个name的使用是否与“用以实例化该template的参数类型”有关而决定的。如果其使用互补相关,那么就以scope of the template declaration来决定name,如果其使用互有关联,那么就以scope of the template instantiation来决定name。

7.2 异常处理

7.3 执行期类型识别




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值