-
构造函数不能是虚函数
- 因为派生类不能继承基类的构造函数,将构造函数声明为虚函数没有意义。
- 构造函数用于在创建对象时进行初始化工作,在执行构造函数之前对象尚未创建完成,虚函数表尚不存在,也没有指向虚函数表的指针,所以此时无法查询虚函数表,也就不知道要调用哪一个构造函数。
-
析构函数用于在销毁对象时进行清理工作,可以声明为虚函数,而且有时候必须声明为虚函数。
#include <iostream> using namespace std; //基类 class Base{ public: Base(); ~Base(); protected: char *str; }; //构造函数:分配100个char类型的内存空间 Base::Base(){ str = new char[100]; cout<<"Base constructor"<<endl; } //析构函数:把分配的内存释放掉 Base::~Base(){ delete[] str; cout<<"Base destructor"<<endl; } //派生类 class Derived: public Base{ public: Derived(); ~Derived(); private: char *name; }; Derived::Derived(){ name = new char[100]; cout<<"Derived constructor"<<endl; } Derived::~Derived(){ delete[] name; cout<<"Derived destructor"<<endl; } int main(){ Base *pb = new Derived(); //基类指针,指向派生类 delete pb; cout<<"-------------------"<<endl; Derived *pd = new Derived(); //派生类指针,指向基类 delete pd; return 0; }
// 指针pd只调用了基类的析构函数,没有调用派生类的析构函数 Base constructor Derived constructor Base destructor ------------------- // 指针pd同时调用了基类和派生类的析构函数 Base constructor Derived constructor Derived destructor Base destructor
-
为什么基类指针pb,不会调用派生类的析构函数?
- 因为这里的析构函数是非虚函数,通过指针访问非虚函数时,编译器会根据指针的类型来确定要调用的函数;
- 也就是说,指针指向哪个类就调用哪个类的函数;
- pd是基类指针,所以不管它指向基类的对象还是指向派生类的对象,始终都调用基类的析构函数。
-
为什么派生类指针pd,会调用派生类和基类的析构函数?
- 派生类析构函数始终会调用基类的析构函数,并且这个过程是隐式完成的。
#include <iostream> using namespace std; //基类 class Base{ public: Base(); //构造函数 virtual ~Base(); //析构函数 protected: char *str; }; Base::Base(){ str = new char[100]; cout<<"Base constructor"<<endl; } Base::~Base(){ delete[] str; cout<<"Base destructor"<<endl; } //派生类 class Derived: public Base{ public: Derived(); ~Derived(); private: char *name; }; Derived::Derived(){ name = new char[100]; cout<<"Derived constructor"<<endl; } Derived::~Derived(){ delete[] name; cout<<"Derived destructor"<<endl; } int main(){ Base *pb = new Derived(); delete pb; cout<<"-------------------"<<endl; Derived *pd = new Derived(); delete pd; return 0; }
/*运行结果*/ Base constructor Derived constructor Derived destructor Base destructor ------------------- Base constructor Derived constructor Derived destructor Base destructor
-
将基类的虚构函数声明为虚函数后,派生类的析构函数也会自动成为虚函数
-
这个时候编译器会忽略指针的类型,而根据指针的指向来选择函数
-
大部分情况下都应该将基类的析构函数声明为虚函数,否则就有内存泄漏的风险。