为什么构造函数不能为虚函数?
参考回答:
在类中,构造函数用于初始化对象及相关操作。
构造函数是不能声明为虚函数的,因为虚函数对应一个virtual table(虚函数表),这个表的地址是存储在对象的内存空间的。
而在执行构造函数前,对象尚未完成创建,内存都没有被分配,所以无法去查询虚函数表,它不存在,因此也就无法得知该调用哪一个函数了。
为什么析构函数要定义为虚函数?
参考回答:
析构函数则用于销毁对象完成时相应的资源释放工作。
(当一个类是基类的时候,才会把析构函数写成虚函数。)
当基类的析构函数不为虚的话,其子类中所有的成员变量的类中分配的内存可能将泄漏。
将基类的析构函数设为virtual型,则所有的基类的派生类对象的析构函数都会自动设置为virtual型,这保证了任何情况下,不会出现由于析构函数没有被调用而导致的内存泄漏。
具体解释如下:
class base {
}
class derived: public base{
}
base *ptr = new derived();
delete ptr;
这段代码的运行结果是:
base constructor!
derived constructor!
base destructor!
在主函数中创建了一个基类类型的指针,指针指向一个派生类对象。
可以看出,最后的运行结果:程序并未调用派生类的析构函数,不调用派生类的析构函数则会导致b指针所指向的1000整型存储空间不会被释放,如此一来造成了内存泄漏。
为了解决这个问题,可以将基类的析构函数声明为虚函数,修改后程序运行结果为:
base constructor!
derived constructor!
derived destructor!
base destructor!
当基类的析构函数声明为虚函数后,派生类的析构函数也自动成为虚析构函数。
在主函数中基类指针p指向的是派生类对象,当delete释放p指针所指向的存储空间时,会执行派生类的析构函数,派生类的析构函数执行完后会紧接着执行基类的析构函数,以释放从基类基础过来的成员变量所消耗的资源。
问题继续来临:
虚函数的工作原理?
有关虚函数的几个知识点
- 构造函数不能是虚函数
- 析构函数应该是虚函数
- 如果基类析构不加virtual关键字,那么派生类对象在释放时,只会调用基类析构。
- 加上virtual后,会先调用派生类析构,再调用基类析构。
- 这意味着,即使基类不需要显示析构提供服务,也应该提供虚析构函数,即使它不执行任何任务。
- 友元函数不能是虚函数,因为友元不是类成员