构造函数或者析构函数中调用虚函数会怎样
在C++中,构造函数和析构函数中调用虚函数会导致一些行为与预期不符。具体来说:
- 构造函数中调用虚函数
当在构造函数中调用虚函数时,调用的是当前类的版本,而不是派生类的版本。这是因为在构造函数执行期间,派生类的对象尚未完全构造完毕,因此虚函数表(vtable)还没有更新为派生类的版本
#include <iostream>
class Base {
public:
Base() {
std::cout << "Base constructor called." << std::endl;
// 调用虚函数
this->show();
}
virtual void show() {
std::cout << "Base show called." << std::endl;
}
virtual ~Base() {
std::cout << "Base destructor called." << std::endl;
// 调用虚函数
this->show();
}
};
class Derived : public Base {
public:
Derived() {
std::cout << "Derived constructor called." << std::endl;
}
virtual void show() override {
std::cout << "Derived show called." << std::endl;
}
virtual ~Derived() {
std::cout << "Derived destructor called." << std::endl;
}
};
int main() {
Derived d;
return 0;
}
输出结果:
Base constructor called.
Base show called.
Derived constructor called.
Derived destructor called.
Base destructor called.
Base show called.
析构函数中调用虚函数
类似地,当在析构函数中调用虚函数时,调用的也是当前类的版本,而不是派生类的版本。这是因为在派生类的析构函数执行后,对象的类型被认为是基类,因此虚函数表也恢复到基类的版本。
总结
构造函数中调用虚函数:调用当前类的版本,因为派生类对象还未完全构造。
析构函数中调用虚函数:调用当前类的版本,因为派生类对象已经开始析构。
这种行为是为了避免在构造和析构过程中调用尚未初始化或已经销毁的派生类成员,从而导致未定义行为。为了避免这种问题,最好避免在构造函数和析构函数中调用虚函数。