虚函数:特殊函数的讨论

来源:互联网 发布:河南省网络教研室 编辑:程序博客网 时间:2024/05/21 07:12

构造函数和析构函数

正如我们所见,在构造和析构过程中,有时需要初始化一些隐藏的成员变量。最坏的情况下,一个构造函数要执行如下操作:

1 * 如果是“最终派生类”,初始化vbptr成员变量,调用虚基类的构造函数;
2 * 调用非虚基类的构造函数
3 * 调用成员变量的构造函数
4 * 初始化虚函数表成员变量
5 * 执行构造函数体中,程序所定义的其他初始化代码

(注意:一个“最终派生类”的实例,一定不是嵌套在其他派生类实例中的基类实例)
所以,如果你有一个包含虚函数的很深的继承层次,即使该继承层次由单继承构成,对象的构造可能也需要很多针对虚函数表的初始化。
反之,析构函数必须按照与构造时严格相反的顺序来“肢解”一个对象。

1 * 合成并初始化虚函数表成员变量
2 * 执行析构函数体中,程序定义的其他析构代码
3 * 调用成员变量的析构函数(按照相反的顺序)
4 * 调用直接非虚基类的析构函数(按照相反的顺序)
5 * 如果是“最终派生类”,调用虚基类的析构函数(按照相反顺序)

在VC++中,有虚基类的类的构造函数接受一个隐藏的“最终派生类 标志”,标示虚基类是否需要初始化。对于析构函数,VC++采用“分层析构模型”,代码中加入一个隐藏的析构函数,该函数被用于析构包含虚基类的类(对于 “最终派生类”实例而言);代码中再加入另一个析构函数,析构不包含虚基类的类。前一个析构函数调用后一个。

虚析构函数与delete操作符

假如A是B的父类,

A* p = new B();

如果析构函数不是虚拟的,那么,你后面就必须这样才能安全的删除这个指针:

delete (B*)p;

但如果构造函数是虚拟的,就可以在运行时动态绑定到B类的析构函数,直接:

delete p;

就可以了。这就是虚析构函数的作用。

实际上,很多人这样总结:当且仅当类里包含至少一个虚函数的时候才去声明虚析构函数。
考虑结构V和W。


析构函数可以为虚。一个类如果有虚析构函数的话,将会象有其他虚函数一样,拥有一个虚函数表指针,虚函数表中包含一项,其内容为指向对该类适用的虚析构函数的地址。这些机制和普通虚函数相同。 虚析构函数的特别之处在于:当类实例被销毁时,虚析构函数被隐含地调用。调用地(delete发生的地方)虽然不知道销毁的动态类型,然而,要保证调用对该类型合适的delete操作符。 例如,当pv指向W的实例时,当W::~W被调用之后,W实例将由W类的delete操作符来销毁。

译者注:

  • V没有定义delete操作符,delete时使用函数库的delete操作符;
  • W定义了delete操作符,delete时使用自己的delete操作符;
  • 可以用全局范围标示符显示地调用函数库的delete操作符。

为 了实现上述语意,VC++扩展了其“分层析构模型”,从而自动创建另一个隐藏的析构帮助函数——“deleting析构函数”,然后,用该函数的地址来替 换虚函数表中“实际”虚析构函数的地址。析构帮助函数调用对该类合适的析构函数,然后为该类有选择性地调用合适的delete操作符。

原创粉丝点击