class A
{
public:
A(){a=0}
virtual ~A(){printf "aaa";}}
private:
int a;
}
class B: public A
{
public:
B(){a=2}
virtual ~B(){printf "bbb";}
}
常常有这样两个面试题目:
1)
A* p = new B;
delete p;
p->a 等于多少?
2)
析构函数的打印顺序.
类A 和 类B的析构函数为什么要定义为虚函数,如果不定义为虚函数会有什么问题或隐患?
其实这两道题目就是考的C++中类的构造函数和析构函数的调用顺序问题,其中第一套题比较简单,大部分面试者都能正确回答,第二道题回答完整的就比较少了,第二题还考到了多态(虚函数)的知识点,多态在后续的文章单独阐述。
构造函数:
对于有集成关系的构造函数,定义子类的对象时,会先调用父类的构造函数,再调用子类的析构函数。
因此第一套题先回调用A的构造函数,此时b.a为0,然后调用B的构造函数,最终b.a的值为2.
析构函数:
对于析构函数,大部分面试者回答的比较简单,回答的不够全面。
删除对象时,调用的第一个析构函数,由析构函数是否是虚函数确定:
1)如果是虚函数,则会调用指针指向的实际对象的类的析构函数,但是析构函数不仅仅是虚函数,它还会自动往上调用基类的析构函数。
2)如果不是虚函数,则由删除指针定义的类型来确定。
这道题中,delete p时,由于是析构函数,则会先调用B的析构函数,再调用A的析构函数
如果不是虚函数,则只会调用A的析构函数。但是如果是 B* p = new B的话,即使不是虚函数,也一样会先调用B的析构函数,再调用A的析构函数。
类成员申请的资源通常都是在析构函数中释放,由于析构函数的这个特点,因此析构函数通常定义为虚函数,因为如果不是虚函数的话,很有可能不会调用到子类的析构函数,导致子类申请的资源没有被释放。