析构函数也可以是虚的,甚至是纯虚的。但是构造函数不能是虚的。
class A { public: virtual ~A()=0; // 纯虚析构函数 };
类型需要虚析构函数的另外一个特征是该类型具有指针成员或引用成员。如果有指针成员和引用成员,则该类型通常需要实现析构函数以及拷贝操作。通常,一个实现了析构函数的类型同时也需要实现拷贝构造函数与拷贝复制函数。
作为一个经验法则:如果你有一个带有虚函数功能的类,则它需要一个虚析构函数,原因如下:
1. 如果一个类有虚函数功能,它经常作为一个基类使用。
2.如果它是一个基类,它的派生类经常使用new来分配。
3.如果一个派生类对象使用new来分配,并且通过一个指向它的基类的指针来控制,那么它经常通过一个指向它的基类的指针来删除它(如果基类没有虚析构函数,结果将是不确定的,实际发生时,派生类的析构函数永远不会被调用)。基类有虚析构函数的话,最底层的派生类的析构函数最先被调用,然后各个基类的析构函数被调用。
当一个类打算被用作其它类的基类时,它的析构函数必须是虚的。考虑下面的例子:
class A { public: A() { ptra_ = new char[10];} ~A() { delete[] ptra_;} // 非虚析构函数 private: char * ptra_; }; class B: public A { public: B() { ptrb_ = new char[20];} ~B() { delete[] ptrb_;} private: char * ptrb_; }; void foo() { A * a = new B; delete a; }
在这个例子中,程序也许不会象你想象的那样运行,在执行delete a的时候,实际上只有A::~A()被调用了,而B类的析构函数并没有被调用!造成内存的泄漏,这是否有点儿可怕? 如果将上面A::~A()改为virtual,就可以保证B::~B()也在delete a的时候被调用了。因此基类的析构函数都必须是virtual的。
避免二义性
如果基类A
B继承A,C继承A
C继承B,C
那么B: public virtual A,
C: public virtual A
如果没有virtual 编译器会报错。有二义性的错误
3.virtual函数
C++多态的精华就是virtual函数。
1.纯虚函数。这个就是virtual void show()=0;类似java中的接口。必须实现。
2.普通虚函数
基类的实现:
#ifndef Memory_C_h
#define Memory_C_h
class C
{
public:
C()
{
NSLog(@"construct c");
}
virtual ~C()
{
NSLog(@"delete c");
}
virtual void show()
{
NSLog(@"showC");
}
private:
int x;
};
#endif
#ifndef Memory_D_h
#define Memory_D_h
class D : public C
{
public:
D(){
NSLog(@"construct d");
}
~D()
{
NSLog(@"delete D");
}
void show()
{
NSLog(@"showD");
}
};
调用的地方:
C* c = new D;
c->show();
delete c;
2013-03-12 23:07:14.809 Memory[868:c07] construct c
2013-03-12 23:07:14.810 Memory[868:c07] construct d
2013-03-12 23:07:14.811 Memory[868:c07] showD
2013-03-12 23:07:14.811 Memory[868:c07] delete D
2013-03-12 23:07:14.812 Memory[868:c07] delete c
【注意】虚函数有默认继承的作用,
如果A中有virtual void show();
D继承A,D中 void show();
E继承D,E中 void show();
D* d = new E;
d->show();
delete d;
结果:
2013-03-12 23:13:19.378 Memory[907:c07] construct c
2013-03-12 23:13:19.379 Memory[907:c07] construct d
2013-03-12 23:13:19.379 Memory[907:c07] construct e
2013-03-12 23:13:19.380 Memory[907:c07] showE
2013-03-12 23:13:19.380 Memory[907:c07] delete E
2013-03-12 23:13:19.381 Memory[907:c07] delete D
2013-03-12 23:13:19.381 Memory[907:c07] delete c