读《C++对象模型》- 构造、解构、拷贝语意学
constructor可能内带大量的隐藏码,因为编译器会扩充每一个constructor,扩充程度视class的继承体系而定。一般而言编译器所做的扩充操作大约如下:
- 记录在member initialization list中的data members初始化操作会被放进constructor的函数本身,并以members的声明顺序为顺序。
- 如果有一个member并没有出现在member initialization之中,但它有一个default constructor,那么该default constructor必须被调用。
- 在2之前,如果class object有virtual table pointer(s),它(们)被设定初值,指向适当的virtual table(s)。
- 在3之前,所有上一层的base class constructors必须被调用,以base class的声明顺序为顺序:
- 如果base class被列于member initialization list中,那么任何明确指定的参数都应该传递过去。
- 如果base class没有被列于member initialization list中,而它有default constructor,那么就调用之。
- 如果base class是多重继承下的第二或后继的base class,那么this指针必须有所调整。
- 在4之前,所有virtual base class constructors必须被调用,从左到右,从最深到最浅:
- 如果class被列于member initialization list中,那么如果有任何明确指定的参数,都应该传递过去。若没有列于list之中,而class中一个default constructor,也应该调用之。
- 此外,class中的每一个virtual base class subobject的偏移量(offset)必须在执行期可被存取。
- 如果class object是最底层的(most-derived)的class,其constructors可能被调用;某些用以支持这个行为的机制必须被放进来。
读《C++对象模型》- Function语意学
一、成员函数的调用方式
1.Nonstatic member functions
C++的设计准则之一就是:nonstatic member function 至少必须和一般的nonmember function有相同的效率。而实际上,编译器内部会将“member函数实体”转换为对等的“nonmember函数实体”。其转化步骤大致如下:
- 改写函数的signature(函数名称+参数数目+参数类型)以安插一个额外的参数到member function中,用以提供一个存取管道,使class object得以调用该函数。该额外参数被称为this指针。
- 将每一个“对nonstatic data member”的存取操作“改为经由this指针来存取”。
- 对member function重新写成一个外部函数。对函数名称进行“mangling”处理,使它在程序中成为独一无二的语汇(比如将参数 类型和返回值类型也编码进来)。
展望2010
本来是想将这里弄成纯技术博客的,想着想着也太单调了,还是配合一下吐槽会比较有美感。
回想起来,前两年日子都是过得比较有压力,当然也有伤感啦。现在听着的歌是《答应不爱你》,感觉还挺好听的。工作这半年多以后,最深的感触就是工作环境比较轻松,大家都很nice,我很喜欢这种气氛,在这里有很大的学习空间,还有的是我经常能够穿拖鞋上班,虽然HR跟我说过上班不要穿人字拖,可是可是……
其实我很怀念那段封闭开发的日子,因为封闭开发感觉很清静,没有在大楼那么吵杂,这样使人能够专心工作。而且项目进度紧,我觉得反而提高自己的专注力,现在工作没有那么紧,虽然可以多点时间学习,但是感觉也颇为有点懒,思维也没有那么活跃。但也不想每天都搞到12点,这样我就没有时间看书了。
读《C++对象模型》- Data语意学
一、Data Member的存取
static data members,会被编译器提出于class之外,并被视为一个global变量(但只在class生命范围之内可见)。每一个member的存取许可(private, protected, public),以及与class的关联,并不会导致任何空间上或执行时间上的额外负担——不论是在个别的class objects或是在static data member本身。每一个static data member只有一个实体,存放在程序的data segment之中。
nonstatic data members直接存放在每一个class object之中。每一个nonstatic data member的偏移量(offset)在编译时期即可获知,甚至如果member属于一个base class subobject(派生自单一或多重继承串链)也是一样。因此,存取一个nonstatic data member,其效率和存取一个C struct member或一个nonderived class的member是一样的。
但是使用继承和指针还是会带一些差异的,如下代码:
// Point3d是一个derived class 其定义就忽略哈 Point3d origin, *pt = &origin; origin.x = 0.0; pt->x = 0.0
从上面代码中,“从origin存取”和“从pt存取”有什么重大的差异?答案是“当Point3d是一个derived class,而在其继承结构中有一个virtual base class,并且被存取的member(如上例中的x)是一个从该virtual base class继承而来的member时,就会有重大的差异“。这时候不能够说pt必然指向哪一种class type(因此也就不知道编译时期这个member真正的offset位置),所以这个存取操作必然延迟至执行期,经由一个额外的间接导引,才能够解决。但如果使用origin,就不会有这个问题,其类型无疑是Point3d Class,而即使它继承自virtual base class,members的offset位置也在编译时期就固定了。
