深入解析C++中的构造函数和析构函数

来源:互联网 发布:sql注入的危害 编辑:程序博客网 时间:2024/06/05 04:06

深入解析C++中的构造函数和析构函数

构造函数:
在类实例化对象时自动执行,对类中的数据进行初始化。构造函数可以重载,可以有多个,但是只能有一个缺省构造函数。

析构函数:
在撤销对象占用的内存之前,进行一些操作的函数。析构函数不能被重载,只能有一个。

调用构造函数和析构函数的顺序:
先构造的后析构,后构造的先折构。它相当于一个栈,先进后出。

#include<iostream>#include<string>using namespace std;class Student{ public:  Student(string,string,string);  ~Student();  void show(); private:  string num;  string name;  string sex;};Student::Student(string nu,string na,string s){ num=nu; name=na; sex=s; cout<<name<<" is builded!"<<endl;}void Student::show(){ cout<<num<<"\t"<<name<<"\t"<<sex<<endl;}Student::~Student(){ cout<<name<<" is destoried!"<<endl;}int main(){ Student s1("001","千手","男"); s1.show(); Student s2("007","纲手","女"); s2.show(); cout<<"nihao"<<endl; cout<<endl; cout<<"NIHAO"<<endl; return 0;}

先构造的千手,结果后析构的千手;后构造的纲手,结果先折构的纲手。

特点:
在全局范围定义的对象和在函数中定义的静态(static)局部对象,只在main函数结束或者调用exit函数结束程序时,才调用析构函数。

如果是在函数中定义的对象,在建立对象时调用其构造函数,在函数调用结束、对象释放时先调用析构函数。

#include<iostream>#include<string>using namespace std;class Student{ public:  Student(string,string);  ~Student();  void show();  string num;  string name;};Student::Student(string nu,string na){ num=nu; name=na; cout<<name<<" is builded!"<<endl<<endl;}void Student::show(){ cout<<num<<"\t"<<name<<endl<<endl;}Student::~Student(){ cout<<name<<" is destoried!"<<endl<<endl;}void fun(){ cout<<"============调用fun函数============"<<endl<<endl;  Student s2("002","自动局部变量");//定义自动局部对象  s2.show(); static Student s3("003","静态局部变量");//定义静态局部变量  s3.show(); cout<<"===========fun函数调用结束=============="<<endl<<endl;}int main(){ Student s1("001","全局变量"); s1.show(); fun(); cout<<"\nthis is some content before the end\n";//这是一段位于main函数结束之前,函数调用之后的内容 cout<<endl; return 0;}




析构函数再探:为什么有的类的析构函数是虚函数?


以下内容转载自:http://blog.163.com/cindy_zhoulixia/blog/static/7361720920083229403237/

所有C++程序员对析构函数都不陌生,由于其简单且易理解,所以都能很快应用。这里我不说这些常用方法,若不知可参考C++书籍。而我这次所想说的是较微妙的技巧,常不被人注意,但却非常非常的重要。看以下代码:

#include <iostream.h>class CFunction{public:CFunction(){data = new char[64];};~CFunction(){delete [] data;};char *data;};class CFunctionEx : public CFunction{public:CFunctionEx(){m_data = new char[64];};~CFunctionEx(){delete [] m_data;};private:char *m_data;};void main(){CFunction *pCFun = new CFunctionEx;delete pCFun;}

你能看出什么问题吗?很显然,有内存泄漏。这是因为当删除pCFun时,它只调用了Cfunction的析构函数而没调用CfunctionEx的析构函数,所以导致内存泄漏。再看下例:

#include <iostream.h>class CBase{public:CBase(){data = new char[64];};~CBase(){delete [] data;};char *data;};class CFunction{public:CFunction(){};~CFunction(){};};class CFunctionEx : public CFunction{public:CFunctionEx(){};~CFunctionEx(){};private:CBase m_cbase;};void main(){CFunction *pCFun = new CFunctionEx;delete pCFun;}

你能看出什么问题吗?这里CfunctionEx和Cfunction中本身并没有分配内存,应该不会有内存泄漏。和上例一样当删除pCFun时,它只调用了Cfunction的析构函数而没调用CfunctionEx的析构函数,但CfunctionEx本身并没分配内存,是什么地方有内存泄漏我不说大家也应该知道了吧。不错是m_cbase,因为它是Cbase的实例且是CfunctionEx成员变量,当CfunctionEx的的析构函数没有被调用时,当然m_cbase的析构函数也没有被调用,所以Cbase中分配的内存被泄漏。

解决以上问题的方法很简单,就是使基类Cfunction的析构函数为虚函数就可以了。很简单,是吗?哈哈……

这样就得出一个结论,当你的基类的析构函数不为虚的话, 其子类中所有的成员变量的类中分配的内存也将可能泄漏。

这一点非常重要,因为很容易被遗漏。我就是为此这才写此文。

这里说的可能是因为,如果程序中没有以上示例类似写法(指用基类指针指向子类实例裕,虚函数是C++的精华,很少有人不用的,由其是在大中型软件项目中),就不会出现本文所说的内存泄漏。看来在基类中使析构函数为虚函数是如此的重要。所以强烈建议在基类中把析构函数声明为虚函数,但是只有你写的类并不做为基类时例外。

以上我在工作中碰到的问题,程序在VC++6中测试,内存泄漏对于一个高效的服务程序来说十分重要。我想可能大家也可能出现过这种问题,所以写出这篇文章,希望能给大家带来帮助。

再举一例

转载自:http://blog.csdn.net/starlee/article/details/619827

我们知道,用C++开发的时候,用来做基类的类的析构函数一般都是虚函数。可是,为什么要这样做呢?下面用一个小例子来说明:    
    有下面的两个类:

#include<iostream>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 *pTest = new ClxDerived;    pTest->DoSomething();    delete pTest;    return 0;}

输出结果是:

Do something in class ClxDerived!
Output from the destructor of class ClxDerived!
Output from the destructor of class ClxBase!

        但是,如果把类ClxBase析构函数前的virtual去掉,那输出结果就是下面的样子了:

Do something in class ClxDerived!
Output from the destructor of class ClxBase!

也就是说,类ClxDerived的析构函数根本没有被调用!一般情况下类的析构函数里面都是释放内存资源,而析构函数不被调用的话就会造成内存泄漏。我想所有的C++程序员都知道这样的危险性。当然,如果在析构函数中做了其他工作的话,那你的所有努力也都是白费力气。
        所以,文章开头的那个问题的答案就是--这样做是为了当用一个基类的指针删除一个派生类的对象时,派生类的析构函数会被调用。
        当然,并不是要把所有类的析构函数都写成虚函数。因为当类里面有虚函数的时候,编译器会给类添加一个虚函数表,里面来存放虚函数指针,这样就会增加类的存储空间。所以,只有当一个类被用来作为基类的时候,才把析构函数写成虚函数。




0 0