构造函数不能声明为虚函数,而析构函数可以声明为虚函数,在有的情景下析构函数必须声明为虚函数。
不建议在构造函数和析构函数里调用虚函数。
构造函数不能声明为虚函数的原因?
构造一个对象时,必须知道对象实际类型,而虚函数是在运行期间确定实际类型的。而在构造一个对象时,由于对象还未构造成功,编译器就无法知道对象的实际类型,是该类本身,还是派生类,还是其他。
虚函数的执行依赖于虚函数表,而虚函数表是在构造函数中进行初始化的,即初始化虚表指针(vptr),使得正确指向虚函数表。而在构造对象期间,虚函数表(vtable)还没有被初始化,将无法进行。
析构函数设为虚函数的原因?
当基类指针指向子类对象的时候,当调用基类的析构函数释放内存时,由于析构函数不具有多态性,因此只会执行基类的析构函数,子类内存无法释放,因此造成内存泄漏。
当将基类的析构函数设定为虚函数的话,当调用基类的析构函数释放内存时,会先去执行子类的析构函数释放子类的内存,之后再调用基类的析构函数,释放基类的内存。
析构函数的作用在对象撤销前把类的对象从内存中撤掉,通常系统只会执行基类的析构函数,不执行派生类的析构函数。
将基类的析构函数声明为虚函数,当撤销基类对象的同时也撤销派生类的对象,这个过程是动态关联完成的。
析构函数设为虚函数的原因是为了防止内存泄露。在继承体系中,当基类的指针或引用指向派生类,用基类delete时,如果析构函数没有声明为虚函数,只能析构基类对象,派生类对象将无法析构。
建议将析构函数设为虚函数。
当想使用子类的指针直接释放子类的对象时,会先执行子类的析构函数,再执行基类的析构函数,再执行基类的基类的析构函数,以此类推!
说明:
使用虚函数,系统会有一定的空间开销。当一个类带有虚函数时,编译系统会为该类构造一个虚函数表,是一个指针数组,存放每个虚函数的入口地址。系统在进行动态关联的时间开销很少,提高了多态性的效率。
编译器生成的析构函数都是非虚的,除非是一个子类,其父类有个虚析构函数,此时的虚函数特性继承自基类。
有虚函数的类,一般情况下要定义一个虚析构函数。
纯虚函数
在有的情景下,基类的虚函数是为了派生类中的使用而声明定义的,但在基类中没有任何意义,此类函数称为纯虚函数,不需要写成空函数的形式,只需要在声明为以下格式:
virtual 函数类型 函数名(形参列表) = 0;
1
纯虚函数是没有函数体的,“=0”并不代表函数的名字不具备函数的功能,不能被调用,在派生类中对该函数定义后,才能具备函数的功能,可以被调用。