写这个博客的原因是因为最近在面试的时候被问过好几次这个问题,但是却一直处于一种模棱两可的状态, 因此今天记录一下这个问题的一个理解已经代码实验的现象.
- 构造函数调用虚函数
都知道虚函数是为了实现多态中的一个动态绑定过程. 而在进入派生类的构造函数之前,会先调用基类的构造函数.
话不多说,先看代码.
class base{
public:
virtual void show(){
cout << "this is base\n" << endl;
}
base(){
show();
}
};
class derived: public base{
public:
virtual void show(){
cout << "this is derived\n" << endl;
}
derived(){
show();
}
};
int main(){
base* test_base = new derived;
delete test_base;
return 0;
}
执行结果为:
总结: 从语法上来说, 构造函数是可以调用虚函数的, 编译并不会有问题(面试被问会不会出现编译报错), 但是这么做起不到并起不到虚函数本身的动态绑定作用, 只会调用自身所在类的对应虚函数, 也就失去了这么做的意义. 同时从结果上也看出了派生类对象构造前先调用基类构造.
- 析构函数调用虚函数
同样的, 都知道析构函数的执行顺序是和构造函数相反的, 是一个从派生类到基类的一个顺序.
class base{
public:
virtual void show(){
cout << "this is base\n" << endl;
}
~base(){
show();
}
};
class derived: public base{
public:
virtual void show(){
cout << "this is derived\n" << endl;
}
~derived(){
show();
}
};
int main(){
cout << "基类指针指向派生类对象的析构输出结果\n" << endl;
base* test_base = new derived;
delete test_base;
cout << "派生类指针指向派生类对象的析构输出结果\n" << endl;
derived* test_drived = new derived;
delete test_drived;
return 0;
}
从结果上看的话, 编译通过且输出了结果, 基类指针指向一个派生类对象, 在析构的时候其仍然是处于一个基类的状态, 因此会调用基类的show()
函数, 而派生类指针指向派生类对象, 其是一个派生类因此会先调用派生类的析构函数,然后再调用基类的析构函数.
- 总结
析构函数和构造函数调用虚函数从语法上是没有问题的, 可以编译通过, 但是这种调用方式并没有什么意义, 不能体现虚函数的动态绑定特性.