前言
在书上说,构造函数和析构函数不能调用需函数,但是有点不解,查了一下,后来终于明白了,主要原因是:
我们知道,虚函数存在的价值是实现多态,为的是用父类的指针或者引用指向子类的对象,调用虚函数的时候,可以根据不同的子类对象调用不同版本的虚函数,可以说,虚函数就是为了多态而生的!!
1.好的如果按照使用者的角度来说:
构造函数的问题
那么在构造函数中调用虚函数会出现什么问题呢,首先我们要知道,构造一个类的对象的时候,如过这个类是一个派生类,那么首先要调用父类的构造函数,先把父类的那部分构造出来,再调用子类的构造函数,把子类的这部分数据初始化,分配好内存,好了,如果父类的构造函数里面调用了虚函数,如果要实现多态的话,那么就是要调用子类版本的虚函数啦,但是,这个时候子类部分的成员变量还没开始分配内存初始化呢,调用子类版本虚函数的话,那么不就出问题了,要虚函数要访问子类成员变量肯定会去访问未知的内存,这就出大事儿了,首先按照使用者的想法,这种做法已经被推翻
析构函数的问题
再说在析构函数中调用虚函数的问题,我们知道,析构函数的调用顺序和构造函数刚好相反,如果调用了父类的析构函数,那就证明子类构造函数已经调用了,子类对象的数据成员部分已经被释放,那么调用需函数的话,要访问子类版本的虚函数,那不可能啊,变量都释放了,你还要去访问这些变量,那么出问题了,所以按照使用者的想法,他的目的也没法达到。
所以,在这俩个函数中调用虚函数是不可能实现多态的,调用虚函数的意义就没有了,有些编译器会在编译的时候报错,有些不会报错,但执行的时候肯定报错那时候就麻烦了,可能你都不会知道错在哪里,所以错误越早发现越好,完毕
按照内存的角度说:
后记:以上其实在构造函数中调用虚函数在语意上是很危险的,因为那种想法很有可能出问题,但是实际上在内存的角度来说,它其实是安全的,因为虚函数的调用的通过vptr 来实现多态的,但是在C++的实现中,vptr的初始化,总是在构造函数调用之后,因此调用的虚函数的版本总是当前所在那个类的版本,虽然从内存的角度来说这是安全的,但是这已经失去了多态的性质,调用的意义就不大了,完全达不到使用者的目的,还不如直接显式这样调用:
class A
{
void virtual f(){}
A(){ A::f(); //这样显式的说明调用本类的那个虚函数 }
}
因此,不推荐在构造函数和析构函数中使用虚函数