构造函数和析构函数中可以调⽤调⽤虚函数吗
可以,虚函数底层实现原理(但是最好不要在构造和析构函数中调⽤) 可以,但是没有动态绑定的效果,⽗类构造函数中调⽤的仍然是⽗类版本的函数,⼦类中调⽤的仍然是⼦类版本的函数。 effictive c++第九条,绝不在构造和析构过程中调⽤virtual,因为构造函数中的base的虚函数不会下降到derived上。⽽是直接调⽤base类的虚函数。绝不在构造和析构函数中调⽤virtual函数:
a) 如果有继承,构造函数会先调⽤⽗类构造函数,⽽如果构造函数中有虚函数,此时⼦类还没有构造,所以此时的对象还是⽗类的,
不会触发多态。更容易记的是基类构造期间,virtual函数不是virtual函数。
b) 析构函数也是⼀样,⼦类先进⾏析构,这时,如果有virtual函数的话,⼦类的内容已经被析构了,C++会视其⽗类,执⾏⽗类的
virtual函数。
c) 总之,在构造和析构函数中,不要⽤虚函数。如果必须⽤,那么分离出⼀个Init函数和⼀个close函数,实现相关功能即可。
原⽂链接:blog.csdn/chen134225/article/details/81564972
第⼀个理由是概念上的。
在概念上,构造函数的⼯作是⽣成⼀个对象。在任何构造函数中,可能只是部分形成对象——我们只能知道基类已被初始化,但并不能知道哪个类是从这个基类继承来的。然⽽,虚函数在继承层次上是“向前”和“向外”进⾏调⽤。它可以调⽤在派⽣类中的函数。如果我们在构造函数中也这样做,那么我们所调⽤的函数可能操作还没有被初始化的成员,这将导致灾难发⽣。
第⼆个理由是机械上的。
当⼀个构造函数被调⽤时,它做的⾸要的事情之⼀就是初始化它的VPTR。然⽽,它只能知道它属于“当前”类——即构造函数所在的类。于是它完全不知道这个对象是否是基于其它类。当编译器为这个构造函数产⽣代码时,它是为这个类的构造函数产⽣代码——既不是为基类,也不是为它的派⽣类(因为类不知道谁继承它)。所以它使⽤的VPTR必须是对于这个类的VTABLE。⽽且,只要它是最后的构造函数调⽤,那么在这个对象的⽣命期内,VPTR将保持被初始化为指向这个VTABLE。但如果接着还有⼀个更晚派⽣类的构造函数被调⽤,那么这个构造函数⼜将设置VPTR指向它的VTABLE,以此类推,直到最后的构造函数结束。VRTP的状态是由被最后调⽤的构造函数确定的。这就是为什么构造函数调⽤是按照从基类到最晚派⽣类的顺序的另⼀个理由。
但是,当这⼀系列构造函数调⽤正发⽣时,每个构造函数都已经设置VPTR指向它⾃⼰的VTABLE。如果
函数调⽤使⽤虚机制,它将只产⽣通过它⾃⼰的VTABLE的调⽤,⽽不是最后派⽣的VTABLE(所有构造函数被调⽤后才会有最后派⽣的VTABLE)。另外,许多编译器认识到,如果在构造函数中进⾏虚函数调⽤,应该使⽤早绑定,因为它们知道晚绑定将只对本地函数产⽣调⽤。⽆论哪种情况,在构造函数中调⽤虚函数都不能得到预期的结果。
——来⾃《C++编程思想》合订本第386页
原⽂链接:blog.csdn/sumup/article/details/78174915
1. 从语法上讲,调⽤完全没有问题。
2. 但是从效果上看,往往不能达到需要的⽬的。
Effective 的解释是:
派⽣类对象构造期间进⼊基类的构造函数时,对象类型变成了基类类型,⽽不是派⽣类类型。多态性与虚函数
同样,进⼊基类析构函数时,对象也是基类类型。
所以,虚函数始终仅仅调⽤基类的虚函数(如果是基类调⽤虚函数),不能达到多态的效果,所以放在构造函数中是没有意义的,⽽且往往不能达到本来想要的效果。
构造函数和析构函数调⽤虚函数时都不使⽤动态联编,如果在构造函数或析构函数中调⽤虚函数,则运⾏的是为构造函数或析构函数⾃⾝类型定义的版本。
原因分析:
(1)不要在构造函数中调⽤虚函数的原因:因为⽗类对象会在⼦类之前进⾏构造,此时⼦类部分的数据成员还未初始化,因此调⽤⼦类的虚函数是不安全的,故⽽C++不会进⾏动态联编。
(2)不要在析构函数中调⽤虚函数的原因:析构函数是⽤来销毁⼀个对象的,在销毁⼀个对象时,先调⽤⼦类的析构函数,然后再调⽤基类的析构函数。所以在调⽤基类的析构函数时,派⽣类对象的数据成员已经“销毁”,这个时再调⽤⼦类的虚函数已经没有意义了。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论