构造函数和析构函数中的虚函数
(一)虚函数简介
虚函数是C++中用于实现多态的机制。核心理念就是通过基类访问派生类定义的函数。由于虚函数的调用借助指针或引用来达到多态的目的,即虚函数调用不是在编译时刻确定的,而是在运行时刻确定的。编译器发现一个类中有定义虚函数,就会为其搞一个虚函数表(VTable),表中的每一项指向一个虚函数,并且一个类只有一个虚函数表(单继承)。
派生类有自己的Vtable,但是派生类的Vtable与基类的Vtable有相同的函数排列顺序,同名的虚函数被放在两个数组的相同位置上。在创建类实例的时候,编译器还会在每个实例的内存布局中增加一个虚指针(vptr)字段,该字段指向本类的VTable。由于基类指针没有得到内存分配,只能通过具有内存分配派生类对象得到函数调用。
(二)构造函数
构造函数不能声明为虚函数。原因是:
1)从存储空间角度
虚函数对应一个虚函数表(vtable),可是这个vtable其实是存储在对象的内存空间的。问题出来了,如果构造函数是虚的,就需要通过 vtable来调用,可是对象还没有实例化,也就是内存空间还没有,无法找到vtable,所以构造函数不能是虚函数。
2)从使用角度
虚函数主要用于在信息不全的情况下,能使重载的函数得到对应的调用。构造函数本身就是要初始化实例,那使用虚函数也没有实际意义呀。所以构造函数没有必要是虚函数。
虚函数的作用在于通过父类的指针或者引用来调用它的时候能够变成调用子类的那个成员函数。而构造函数是在创建对象时自动调用的,不可能通过父类的指针或者引用去调用,因此也就规定构造函数不能是虚函数。
(三)析构函数
析构函数可以声明为虚函数,但基类的虚构函数必须声明为虚函数。原因是:
当需要删除基类指针时,就需要运行析构函数进行清除基类的成员。
-
如果基类析构函数没有声明为虚函数,则通过基类指针只能调用基类的析构函数,导致派生类的析构函数得不到调用,从而致使派生类的成员得不到释放。
-
如果基类的析构函数声明网虚函数,那么通过基类指针就能调用派生类的析构函数,然后派生类析构函数再调用基类的析构函数,释放相应的内存空间。
注意:如果在构造函数或析构函数中调用虚函数,则运行的是构造函数或析构函数自身类型定义的版本。