一个模板只有被使用到,才会被实例化,否则不会被实例化。对于一个实例化后的模板来说,未被调用的成员函数将不会被实例化,只有成员函数被使用时,C++标准才要求实例化他们
目前的编译器,在被一组实际参数实例化之前,只能执行有限的错误检查。
模板中的名称决议
// scope of the template definition
extern double foo ( double );
template < class type >
class ScopeRules
{
public:
void invariant() {
_member = foo( _val );
}
type type_dependent() {
return foo( _member );
}
// ...
private:
int _val;
type _member;
};
//scope of the template instantiation
extern int foo( int );
// ...
ScopeRules< int > sr0;
sr0.invariant();
sr0.type_dependent();
对 invariant 的调用是 double 的那个函数;对 type_dependent 的调用是 int 的那个函数。
模板中对于一个非成员 name 的决议结果,是根据这个 name 的使用是否与“用以实例化该template的参数类型”有关而决定的。如果其使用互不相干,那么以模板声明作用域来决定 name;如果互有关联,那么以模板实例化作用域来决定name。
name与实例化模板的参数相关的例子:比如template<typename T>
然后调用的时候参数有T
那么就是有关联的。
这意味着编译器必须保持两个作用域上下文:
- 模板声明作用域,用于一般的模板类;
- 模板实例化作用域,用于特定实例。
编译器的决议算法必须决定那一个才是合适的作用域,然后再其中搜寻适当的name。
TODO:异常处理后面再补。
7.3 运行期类型识别 (RTTI)
在C++中具备多态性质的 class,就是内含继承而来或者直接声明的虚函数。
将多态类的 type_info 作为一个 slot 加入类的 vtbl 即可。这样的策略可以降低额外负担。每个类对象只需要多花费一个指针。这个指针只需被设定一次,是编译期静态设定的,而非在运行期由类构造函数设定(只有 vptr 是这么设定)
dynamic_cast
运算符提供运行期转型操作。
pfct* pf = dynamic_cast<pfct*>(pt);
dynamic_cast
的真正成本:pfct 的一个类型描述器会被编译器产生,由 pt 指向的类对象的类型描述器*必须在运行期通过vptr获得:
typeid
运算符: typeid
可以返回const type_info&,用以获取类型信息。