一. 内容
-
对于 base-derived 体系,base class 构造函数一定更早被调用
,是的,derived class 对象中的 base class 成分会在 derived class 自身成分被构造之前构造妥当。 -
这意味着在 base class 里调用的 virtual 函数,尚未动态绑定 derived class 的成分,virtual 函数调用的是 base class 里默认的实现。非正式的说法或者更加易懂:
在base class构造期间,virtual函数不是virtual函数。
-
如果在 base class 里可以调用 derived class 的 virtual 函数,那么此时 derived class 尚未被初始化,这将是一张通往不明确行为和彻夜调试的直通车票!条款04提醒我们:确定对象使用前先被初始化。
-
相同道理也适用于析构函数。析构函数会先一层一层向 base class 调用其析构函数,也就是说最顶层的 base class 的析构函数首先被执行。那么此时 derived class 的成员变量对于 base class 也是尚未初始化的。
也就是说在 base class 中,就只能访问到 base class 之上的内容,derived class 相当于尚未初始化,访问就是不明确行为。
-
一个优秀的做法是将
virtual 函数转变成 non-virtual 函数
,并在 derived class 把 non-virtual 函数所需参数传递到 base class 层。也就是说虽然无法使用 virtual 函数从 base class 向下调用,你可以令 derived class 向上传递必要的信息
给 base class 构造函数。 -
比起在成员初值列给予 base class 数据,更佳的方式利用辅助函数创建一个值给 base class 构造函数,可以令此函数为 private static,使得不会使用那些尚未初始化的成员变量,而是通过客户传进去的自定义参数。
二. 总结
- 在构造和析构期间不要调用virtual函数,因为这类调用从不下降至 derived class(比起当前执行构造函数和析构函数的那层)。