整理最后一章的内容,关于模板,异常处理以及运行时类型信息的(RTTI: Run Time Type Information)。
这一节整理关于模板的内容。
1. 模板的具现(instantiation)行为。
当我们声明一个模板类时,对编译器而言,并不会发生什么,对于模板类中的枚举变量也是一样的,我们必须这样写:
Point<float>::Status s;//enum Status {Ongoing, Done}
而不能这样写:
Point::Status s
只有当定义一个类对象,不论是隐式的还是显式的,都会导致模板类的具现,例如:
Point<float> origin;
此时模板类Point中,所有成员变量使用模板参数<typename type>的地方,都会被替换成float,此时该类的布局就像普通类一样,其大小也是可知的。
但是对于成员函数,可能只有被使用过的才会具现出来,这是因为:
a. 空间和时间的考虑,如果此类中存在大量的成员函数,而只有一小部分被使用过了,那么全部具现就显得浪费时间和空间了。
b. 尚未实现的机能,并不是一个模板具现出来的所有类型就一定能够完整的支持一组成员函数所需的运算符。
2. 模板的错误报告。
由于模板类在其具现之前,部分类型未知,所以涉及模板参数有关的类型检验,只有在模板具现之后才能进行,其结果将因具现类型的不同而不同。大多数编译器,面对一个模板的声明,在它被一组实际参数具现之前,只能施以有限的错误检查,所以编译得过得模板类其出错得概率远大于编译得过得普通类。
3. 模板中名称决议(resolution)方式。
考虑如下代码模板定义得范围代码:
//scope of template definition
extern double foo(double);
template <typename type>
class ScopeRules
{
public:
void init()
{
_m = foo(_val);
}
type type_dependency()
{
return foo(_val);
}
private:
int _val;
type _m;
};
如下代码是模板具现得代码范围:
//scope of template instantiation
extern int foo(int);
ScopeRules<int> sr;
在模板具现的代码范围内,有两个foo函数的声明,那么如下代码会调用哪一个:
sr.init();
init()中的_m = foo(_val),调用哪一个foo,记住_val是int类型的,答案与我们期望的不一样,调用的是double foo(double),这是因为,有如下规则,对于一个非成员名字的决议结果,要看该名字是否与用以具现该模板的参数类型有关:
a. 如果不相关,就以scope of template definition来决定名字。
b. 如果相关,就以scope of template instantiation来决定。
上面例子中,foo()与用以具现ScopeRules的参数无关,所以只能调用scope of template definition中的foo,那么没有其他选择,只有double foo(double)。
再看以下例子:
sr.type_dependency();
根据以上规则,会从
scope of template instantiation来决议调用哪一个foo,而此时type是int类型,所以会调用int foo(int)版本。注意如果找不到匹配参数的foo,会报错误。
下片会继续整理异常处理相关的内容。