Skip to content

Latest commit

 

History

History
17 lines (8 loc) · 2.91 KB

构造函数中可以调用虚函数吗.md

File metadata and controls

17 lines (8 loc) · 2.91 KB

先说结论:理论可以,但是真的去这么做了,会出大问题,所以一般情况下我们不允许这么做。

让我们来具体分析下:

​ 首先,在C++编程语言中,构造函数中是可以调用虚函数的,C++的规则里面并没有任何对于这方面的限制,但是考虑一个问题,假设有两个对象,他们分别为继承关系,因为当一个类对象(包括派生类)正在被创建时,其类型会逐步从基类变化到最终的派生类。如果在这个过程中调用了虚函数,那么这个虚函数调用将不会下降到更深层次的派生类。

​ 具体来说,如果在基类的构造函数中调用了虚函数,并且这个虚函数在某个派生类中被重写了,那么在创建这个派生类的对象时,虚函数调用将只会执行基类版本的虚函数,而不会执行派生类版本的虚函数。这是因为,此时派生类部分的对象还没有被完全构造好,所以不能调用派生类的成员函数。

​ 至于为什么会这样,主要是原因在于C++中的虚函数通过一个称为vtable(虚表)的机制来实现动态绑定。每个包含虚函数的类都有一个与之关联的虚表,其中包含了指向该类的虚函数的指针。

​ 当一个对象被创建时,它的构造函数会先调用其基类的构造函数,然后按照声明顺序初始化其成员,并最后执行其自身的构造函数代码。**当在一个构造函数中调用虚函数时,由于此时正在构造的对象尚未完成构造,其类型被视为当前正在执行的构造函数所在的类,而不是最终派生类。**因此,如果在基类的构造函数中调用虚函数,将使用基类的虚表,从而调用基类版本的虚函数,而不是派生类版本的虚函数。

​ 至于为什么不是最终派生类,我们都知道,虚函数表只会被创建一份,但是具体在什么地方创建,这个取决于编译器如何实现,但是他的虚函数表指针一般会放在对象头部,也就是说,每个类只有一个虚函数表,但是每个对象都有自己的虚函数表指针。这意味着,同一类型的所有对象都共享同一个虚函数表的内容,但是他们各自的虚函数表指针可能指向不同的虚函数表(如果它们是不同类型的对象)。这也是为什么派生类可以覆盖基类的虚函数的原因:因为派生类的虚函数表中,对应的函数指针会被更新以指向派生类的版本。而在现在这个情况,由于派生类并未构造完成,所以派生类的的构造函数调用的虚函数只能参考基类而不是派生类,从而导致出现错误

​ 总的来说,虽然技术上允许在构造函数中调用虚函数,但是实际操作中却应该避免。一般来说,构造函数应该尽量简单,只做必要的初始化工作,而将复杂的逻辑放入其他成员函数中。