C++ 父类虚析构函数
(1)C++虚函数 :
1). C++ 多态 :
将子类对象指针赋值给父类指针,然后通过父类指针来调用
子类中重写的虚函数。
如果在重写的函数不是虚函数,那么调用的还是父类的函数,
而不是子类中重写的函数。
2). 析构函数工作方式 :
( 派生类的析构函数会自动调用其基类的析构函数。)
最底层的派生类(most derived class)的析构函数最先被调用,然后调用每一个基类的析构函数。
在C++中,当一个派生类对象通过使用一个基类指针删除,而这个基类有一个非虚的析构函数,则结果是未定义的。运行时比较有代表性的后果是对象的派生部分不会被销毁。然而,基类部分很可能已被销毁,这就导致了一个古怪的“部分析构”对象,这是一个泄漏资源。
3). C++父类虚析构函数适用条件 :
通过父类指针来删除子类对象时,适用父类的虚析构函数,
保证子类的析构函数以及父类的
析构函数都得到调用。
一般如果不做基类的类的析构函数一般不声明为虚函数,
因为虚函数的实现要求对象携带额外的信息.
4) 父类中 纯虚 析构函数 的声明 与定义: (不是声明)
1. 纯虚成员函数通常没有定义;它们是在抽象类中声明,
然后在派生类中实现。比如说下面的例子:
class File //an abstract class
{
public:
virtual int open(const string & path, int mode=0x666)=0;
virtual int close()=0;
//...
};
2. 在某些情况下,我们却需要定义一个纯虚成员函数,而不仅仅是声明它。最常见的例子是纯虚析构函数。
class File //abstract class
{
public:
virtual ~File()=0; //declaration of a pure virtual dtor
};
File::~File() {} //definition of dtor
派生类的析构函数会自动调用其基类的析构函数。这个过程是递归的,最终,抽象类的纯虚析构函数也会被调用。
如果纯虚析构函数只被声明而没有定义,那么就会造成运行时(runtime)崩溃。
纯虚析构函数的哑元实现(dummy implementation,即空实现)能够保证这样的代码的安全性。
(2)C++中 多态时,父类虚析构函数,是为了防止调用父类析构函数,
而不调用子类析构函数,防止内存泄露。
(3)C++ 中,调用子类的析构函数时,先执行之类的析构函数,
然后在执行父类的析构函数。
范例一:
#include
using namespace std;
class ClxBase{
public:
ClxBase() {};
~ClxBase() {cout << "Output from the destructor of class ClxBase!" << endl;};
void DoSomething() { cout << "Do something in class ClxBase!" << endl; };
};
class ClxDerived : public ClxBase{
public:
ClxDerived() {};
~ClxDerived() { cout << "Output from the destructor of class ClxDerived!" << endl; };
void DoSomething() { cout << "Do something in class ClxDerived!" << endl; };
};
int main(){
ClxDerived *p = new ClxDerived;
p->DoSomething();
delete p;
return 0;
}
运行结果:
Do something in class ClxDerived!
Output from the destructor of class ClxDerived!
Output from the destructor of class ClxBase!
在main函数中用继承类的指针去操作继承类的成员,
释放指针P的过程是:先释放继承类的资源,再释放基类资源.
范例二:
#include
using namespace std;
class ClxBase{
public:
ClxBase() {};
~ClxBase() {cout << "Output from the destructor of class ClxBase!" << endl;};
void DoSomething() { cout << "Do something in class ClxBase!" << endl; };
};
class ClxDerived : public ClxBase{
public:
ClxDerived() {};
~ClxDerived() { cout << "Output from the destructor of class ClxDerived!" << endl; };
void DoSomething() { cout << "Do something in class ClxDerived!" << endl; }
};
int main(){
ClxBase *p = new ClxDerived;
p->DoSomething();
delete p;
return 0;
}
输出结果:
Do something in class ClxBase!
Output from the destructor of class ClxBase!
在main函数中用基类的指针去操作继承类的成员,释放指针P的过程是:只是释放了基类的资源,而没有调用继承类的析构函数.调用 dosomething()函数执行的也是基类定义的函数.
一般情况下,这样的删除只能够删除基类对象,而不能删除子类对象,形成了删除一半形象,造成内存泄漏.
范例三:
#include
using namespace std;
class ClxBase{
public:
ClxBase() {};
virtual ~ClxBase() {cout << "Output from the destructor of class ClxBase!" << endl;};
virtual void DoSomething() { cout << "Do something in class ClxBase!" << endl; };
};
class ClxDerived : public ClxBase{
public:
ClxDerived() {};
~ClxDerived() { cout << "Output from the destructor of class ClxDerived!" << endl; };
void DoSomething() { cout << "Do something in class ClxDerived!" << endl; };
};
int main(){
ClxBase *p = new ClxDerived;
p->DoSomething();
delete p;
return 0;
}
运行结果:
Do something in class ClxDerived!
Output from the destructor of class ClxDerived!
Output from the destructor of class ClxBase!
范例四:
#include
class Base
{
public:
Base() {data = new char[64]; }
~Base(){delete [] data;}
private:
char *data;
};
class BaseEx: public Base
{
public:
BaseEx(){m_data = new char[64];}
~BaseEx(){delete [] m_data;}
private:
char *m_data;
// 子类中又定义的成员。
};
void main()
{
Base*pCBase = new BaseEx;
delete pCBase ;
}
很显然,上述的程序有内存泄漏。这是因为当删除pCBase时,
它只调用了Base的析构函数而没调用BaseEx的析构函数,
所以导致内存泄漏。