1.首先要明确的是:C++继承的时候,派生类中包含整个完整的基类子对象。但是在派生类中,有一些方法应该不是一般的继承,比如 构造、析构、拷贝构造...(就是那些在用户未定义时,由系统自动生成默认方法的那些成员方法)这些方法应该是 逐级调用的关系,而不是 “继承” 关系 ... 子类有自己的构造和析构函数
以下代码作为佐证:
// extend_test.cpp : 定义控制台应用程序的入口点。
#include "stdafx.h"
#include <iostream>
using namespace std;
class CA
{
public:
CA(){cout<<"CA constructor"<<endl;}
~CA(){cout<<"CA desstructor"<<endl;}
};
class CB:public CA
{
public:
CB(){cout<<"CB constructor"<<endl;}
~CB(){cout<<"CB desstructor"<<endl;}
};
class CC:public CB
{
public:
CC(){cout<<"CC constructor"<<endl;}
~CC(){cout<<"CC desstructor"<<endl;}
};
int _tmain(int argc, _TCHAR* argv[])
{
CC *p = new CC() ;
delete p;
return 0;
}
程序的运行结果为:
CA constructor
CB constructor
CC constructor
CC desstructor
CB desstructor
CA desstructor
请按任意键继续. . .
2.对以上述代码,如果我们修改main函数如下:
int _tmain(int argc, _TCHAR* argv[])
{
CA *p = new CC() ;
delete p;
return 0;
}
其他不变的话,运行结果如下:
CA constructor
CB constructor
CC constructor
CA desstructor
请按任意键继续. . .
可以看到出问题了,只调用了CA的析构函数,CB和CC都没有调用,如果改成如下:
int _tmain(int argc, _TCHAR* argv[])
{
CB *p = new CC() ;
delete p;
return 0;
}
可以发现结果为:
CA constructor
CB constructor
CC constructor
CB desstructor
CA desstructor
请按任意键继续. . .
如果我们修改基类CA如下:
class CA
{
public:
CA(){cout<<"CA constructor"<<endl;}
virtual ~CA(){cout<<"CA desstructor"<<endl;}
};
运行则会发现,结果又对了
CA constructor
CB constructor
CC constructor
CC desstructor
CB desstructor
CA desstructor
请按任意键继续. . .
我们有如下结论:
当基类的析构函数是虚析构函数,是根据指针的类型调用析构函数;
当积累的析构函数不是虚析构函数时,是根据指针指向对象的类型调用析构函数。
我们在设计一个类的时候,如果类至少拥有一个虚函数,或者说基类被设计用于多态,在这种情况下,一个派生类的对象可能通过一个基类指针来进行操作,然后进行销毁,如果这样的话,那么这个基类的析构函数要设置成虚的,有些类虽然是基类,但是不是用于多态的,没有虚函数,没有被设计成允许经由基类接口派生类对象进行操作,那么也无需设成虚析构函数,毕竟增加了开销。
3.如果我们将代码修改如下:
// extend_test.cpp : 定义控制台应用程序的入口点。
#include "stdafx.h"
#include <iostream>
using namespace std;
class CA
{
public:
CA(){cout<<"CA constructor"<<endl;}
~CA(){cout<<"CA desstructor"<<endl;}
};
class CB:public CA
{
public:
CB(){cout<<"CB constructor"<<endl;}
virtual ~CB(){cout<<"CB desstructor"<<endl;}
};
class CC:public CB
{
public:
CC(){cout<<"CC constructor"<<endl;}
~CC(){cout<<"CC desstructor"<<endl;}
};
int _tmain(int argc, _TCHAR* argv[])
{
CA *p = new CC() ;
delete p;
return 0;
}
运行时会报内存错误:即CA的析构函数不是虚的,而CB或者CC的析构函数是虚拟的,那么在调用delete p;会出现内存错误Expression:_BLOCK_TYPE_IS_VALID(pHead->nBlockUse)
_BLOCK_TYPE_IS_VALID是用来检测内存有效性宏中的一个,这个错误说明指针使用出现了
是因为继承类中出现了虚函数,所以多了一个指向虚函数表的指针,而基类中没有虚函数,所以没有这个指针
所以delete的时候出现了内存错
为了验证他我们修改代码如下:
// extend_test.cpp : 定义控制台应用程序的入口点。
#include "stdafx.h"
#include <iostream>
using namespace std;
class CA
{
public:
CA(){cout<<"CA constructor"<<endl;}
~CA(){cout<<"CA desstructor"<<endl;}
virtual void test() {
}
};
class CB:public CA
{
public:
CB(){cout<<"CB constructor"<<endl;}
virtual ~CB(){cout<<"CB desstructor"<<endl;}
};
class CC:public CB
{
public:
CC(){cout<<"CC constructor"<<endl;}
~CC(){cout<<"CC desstructor"<<endl;}
};
int _tmain(int argc, _TCHAR* argv[])
{
CA *p = new CC() ;
delete p;
return 0;
}
即加入一个空的无关虚函数,运行无错。
3.如果我们修改代码如下:
// extend_test.cpp : 定义控制台应用程序的入口点。
#include "stdafx.h"
#include <iostream>
using namespace std;
class CA
{
public:
CA(){cout<<"CA constructor"<<endl;}
virtual ~CA(){cout<<"CA desstructor"<<endl;}
};
class CB:public CA
{
public:
CB(){cout<<"CB constructor"<<endl;}
~CB(){cout<<"CB desstructor"<<endl;}
};
class CC:public CB
{
public:
CC(){cout<<"CC constructor"<<endl;}
~CC(){cout<<"CC desstructor"<<endl;}
};
int _tmain(int argc, _TCHAR* argv[])
{
void *p = new CC() ;
delete p;
return 0;
}
运行结果为:
CA constructor
CB constructor
CC constructor
请按任意键继续. . .
一个析构函数没有调用.
如果*p是void,那就什么析构都不调用了。
本文到这里就结束了,重要的是记住,在实现多态时,应该将基类的析构函数设为虚函数。
本人为初学者,如有不对,还请指教。
参考:http://wxdlut.blog.163.com/blog/static/12877015820107105119657/