深度探索C++对象模型 个人总结 第七章 站在对象模型的尖端
站在对象模型的尖端
7.1Template
Template的“实例化”行为
一个class object的定义会导致template class的“实例化”,但未被使用的member functions不应该被“实例化”
实例化具体时间不做要求,可在编译期也可在链接期。
对于编译器在它被一组实际参数实例化之前只能施行有限的错误检查
Template中的名称决议法
template之中,对于一个nonmember name的决议结果是根据这个name的使用是否与“用以实例化该template的参数类型”有关而决定的。如果其使用互不相干,那么就以“scope of the template declaration”来决定name,否则就以“scope of the template instantiation”来决定name
“scope of the template declaration”:用以专注一般的template class
“scope of the template instantiation”:用以专注特定的实例
Member Function的实例化行为
如果一个virtual function被实例化,其实例化紧跟在其class 的实例化点之后
7.2异常处理
1.为了维护执行速度,编译器可以在编译时期建立起用于支持的数据结构。这会使程序的大小发生膨胀,但编译器可以几乎忽略这些结构,直到整个exception被抛出来
2.为了维护程序的大小,编译器可以在执行期建立起用于支持的数据结构。这会影响程序的执行速度,但意味着编译器只有在必要的时候才建立那些数据结构
C++的exception handling由三个主要得语汇组件构成:
1.一个throw子句。它在程序某处发出一个exception.被丢出去的exception可以是内建类型,也可以是使用者自定义类型
2.一个或多个catch子句。每一个catch子句都是一个exception handler。它用来表示说,这个子句准备处理某种类型的exception,并且在封闭的大括号区段中提供实际的处理程序。
3.一个try区段,它被围绕以一系列的叙述句,这些叙述句可能会引发catch子句起作用。
当一个exception被丢出去时,控制权会从函数调用中被释放出来,并寻找一个吻合的catch子句。如果都没有吻合者,那么默认的处理例程会被调用。当控制权被放弃后,堆栈中的每一个函数调用也就被推离。这个程序称为unwinding the stack。在每一个函数被推离堆栈之前,函数的local class objects的destructor会被调用。
对Exception Handing的支持
当一个exception发生时,编译系统必须完成以下事情:
1.检验发生throw操作的函数
2.决定throw操作是否发生在try区段中;
3.若是,编译系统必须把exception type拿来和每一个catch子句比较
4.如果比较吻合,流程控制应该交到catch子句中;
决定throw是否发生在一个try区段中
如果throw的发生并不在try区段中,或没有一个catch子句吻合,那么系统必须
(a)摧毁所有active local objects,
(b)从堆栈中将当前的函数“unwind”掉
(c)进行到程序堆栈中的下一个函数中去,然后重复上述步骤2~5
将exception的类型和每一个catch子句的类型作比较
对于每一个被丢出来的exception,编译器必须产生一个类型描述器,对exception的类型进行编码。如果那是一个derived type,则编码内容必须包括其所有base class的类型信息,只编进public base class的类型是不够的,因为这个exception可能被一个member function捕捉,而在一个member function的范围之中,在derived class和nonpublic base class之间可以转换。
每一个函数会产生一个exception表格,它描述与函数相关的各区域,任何必要的善后码(cleanup code,被local class object destructors调用 ),以及catch子句的位置(如果某个区域是在try区段之中)。
当一个实际对象在程序执行时被抛出,会发生什么事?
当一个exception被丢出时,exception object会被产生出来并通常放置在相同形式的exception数据堆栈中。从throw端传染给catch子句的是exception object的地址、类型描述器(或是一个函数指针,该函数会传回与该exception type有关的类型描述器对象),以及可能会有的exception object描述器(如果有人定义它的话)
7.3执行期类型识别
Type-Safe Downcast
欲支持type_safe downcast,在object空间和执行时间上都需要一些额外负担
1.需要额外的空间以存储类型信息,通常是一个指针,指向某个类型信息节点
2.需要额外的时间以决定执行期的类型,因为,正如其名所示,这需要在执行期才能决定
大量使用多态或使用内建数据以及非多态设备之间具有冲突
Type-Safe Dynamic Cast
dynamic_cast运算符可以在执行期决定真正的类型,如果downcast是安全的(也就是说,如果base type pointer指向一个derived class object),这个运算符会传回被适当转型过的指针。如果downcast不是安全的,这个运算符会传回0.
References并不是Pointers
dynamic_cast运算符也适用于reference身上。然而对于一个non-type-safe cast,其结果不会与施行于指针的情况相同。因为,一个reference不可以像指针那样“把自己设为0便代表了"no objet"”,若将一个reference设为0,会引起一个临时性对象(拥有被参考到的类型)被产生出来,该临时对象的初值为0,这个referebce然后被设定成为该临时对象的一个别名(alians)。因此当dynamic_cats运算符施行于一个reference时,不能够提供对等于指针情况下的那一组true/false,取而代之的是,会发生下列事情:
1.如果reference真正参考到适当的derived class(包括下一层或下下一层或下下下一层或。。。),downcast会被执行而程序可以继续进行
2.如果reference并不真正是某一种derived class,那么,由于不能够传回0,遂丢出一个bad_cast exception
typeid运算符
使用typeid运算符,就有可能以一个reference达到相同的执行期替代路线.typeid运算符传回一个const reference,类型为type_info(除了适用于多态也适用于内置类型以及非多态的使用者自定类型)
7.4效率有了,弹性呢?
动态共享数据库(Dynamic Shared Libraries)