构造函数不能是虚函数,主要有两个原因: 1.派生类不能继承基类的构造函数,因此把基类的构造函数声明为虚函数没有意义,无法实现多态; 2.C++中的构造函数用来的在创建对象的时候进行初始化工作,在执行构造函数的时候,对象尚未创建完成,虚函数表这个时候还不存在,也没有指向虚函数表的指针,所以此时还无法查询虚函数表。也就不知道调用哪一个构造函数。 析构函数用来在销毁对象的时候进行清理工作,可以声明为虚函数,有时必须声明为虚函数。 #include<iostream> using namespace std; class Base{ public: Base(); ~Base(); protected: char *str; }; Base::Base(){ str=new char[100]; cout<<"Base constractor"<<endl; } Base::~Base(){ delete[] str; cout<<"Base deconstractor"<<endl; } class Derived:public Base{ public: Derived(); ~Derived(); private: char *name; }; Derived::Derived(){ name=new char[100]; cout<<"Dervied constractor"<<endl; } Derived::~Derived(){ delete[] name; cout<<"Derived deconstractor"<<endl; } int main() { Base *pb = new Derived(); delete pb; cout<<"-----------------------"<<endl; Derived *pd = new Derived(); delete pd; } 执行结果: Base constractor Dervied constractor Base deconstractor ----------------------- Base constractor Dervied constractor Derived deconstractor Base deconstractor 从运行结果可以看出,语句 在本例中,不调用派生类的析构函数会导致 name 指向的 100 个 char 类型的内存空间得不到释放;除非程序运行结束由操作系统回收,否则就再也没有机会释放这些内存。这是典型的内存泄露。 为什么delete pb不会调用派生类的析构函数呢? 因为这里的析构函数是非虚函数,通过指针访问非虚函数时候,编译器会根据指针是类型来调用析构函数。也就是说,指针是什么类型,就调用哪个类的析构函数。如这里pb是基类指针,就调用基类的析构函数。 为什么delete pd会同时调用基类和派生类的析构函数? pd 是派生类的指针,编译器会根据它的类型匹配到派生类的析构函数,在执行派生类的析构函数的过程中,又会调用基类的析构函数。派生类析构函数始终会调用基类的析构函数。 更改上面的代码,把析构函数更改虚函数: #include<iostream> using namespace std; class Base{ public: Base(); virtual ~Base(); protected: char *str; }; Base::Base(){ str=new char[100]; cout<<"Base constractor"<<endl; } Base::~Base(){ delete[] str; cout<<"Base deconstractor"<<endl; } class Derived:public Base{ public: Derived(); ~Derived(); private: char *name; }; Derived::Derived(){ name=new char[100]; cout<<"Dervied constractor"<<endl; } Derived::~Derived(){ delete[] name; cout<<"Derived deconstractor"<<endl; } int main() { Base *pb = new Derived(); delete pb; cout<<"-----------------------"<<endl; Derived *pd = new Derived(); delete pd; } 执行结果: Base constractor Dervied constractor Derived deconstractor Base deconstractor ----------------------- Base constractor Dervied constractor Derived deconstractor Base deconstractor 将基类的析构函数声明为虚函数后,派生类也会自动称为虚函数,这个时候,编译器会忽略指针类型,而是根据指针的指向来调用函数,也就是说,指针指向那个对象就调用那个对象的函数。 pb、pd 都指向了派生类的对象,所以会调用派生类的析构函数,继而再调用基类的析构函数。如此一来也就解决了内存泄露的问题。 实际开发中,一旦我们自己定义了析构函数,就是希望在对象销毁时用它来进行清理工作,比如释放内存、关闭文件等,如果这个类又是一个基类,那么我们就必须将该析构函数声明为虚函数,否则就有内存泄露的风险。也就是说,大部分情况下都应该将基类的析构函数声明为虚函数。
|
|
来自: 昵称70747151 > 《待分类》