C++类的构造与析构特点及作用详解
一、类的构造函数什么是构造函数和类具有相同名称并且没有返回值类型的函数就是类的构造函数概念模糊、直接举例123456789101112#include stdio.h#include windows.hstructTest{Test()// 和类具有相同的名、并且没有返回值{}};intmain(){return0;}构造函数的特点直接先来说特点吧然后论证1、构造函数在定义对象的时候被调用2、构造函数可以进行函数重载可以有很多个3、创建对象时默认调用的是无参构造证明1构造函数在定义对象的时候被调用论证如下:1234567891011121314#include stdio.hstructTest{Test(){printf(你调用了构造函数\n);// 此处下断点、如果该函数被调用肯定会停下来。}};intmain(){Test te;printf(接力\n);return0;}我们在Test()构造的输出语句上加断点、当程序调用Test的printf肯定会停下来这个时候我们转到反汇编单步步过、直到函数返回之后就能知到刚刚是在哪里调用的构造函数了vs2010F7编译、F5调试、ALT8反汇编F10一直运行到返回这里编译器做了优化可以直接看出来是在Test定义对象的时候调用了构造。证明2构造函数可以进行函数重载可以有很多个论证如下12345678910111213141516171819202122232425#include stdio.h#include Windows.hstructTest{Test(){printf(你调用了构造函数\n);// 此处下断点、如果该函数被调用肯定会停下来。}Test(inta){printf(重载%d\n,a);}Test(inta,intb){printf(重载%d\n,ab);}};intmain(){Test te;Test te1(1);Test te2(1,1);// 注意、调用有参的构造函数时需要传递参数system(pause);return0;}重载了两个注意调用有参数的构造时需要传递参数。运行可以通过证明3创建对象时默认调用的是无参构造论证如下12345678910111213141516171819#include stdio.h#include Windows.hstructTest{Test(inta){printf(重载%d\n,a);}Test(inta,intb){printf(重载%d\n,ab);}};intmain(){Test te;// 普通定义对象的方式、不带参数system(pause);return0;}首先我们删除无参构造看看能否编译通过不可以然后删除有参构造123456789101112131415#include stdio.h#include Windows.hstructTest{Test(){printf(你调用了构造函数\n);// 此处下断点、如果该函数被调用肯定会停下来。}};intmain(){Test te;system(pause);return0;}可以全部都加上1234567891011121314151617181920212223#include stdio.h#include Windows.hstructTest{Test(){printf(你调用了构造函数\n);// 此处下断点、如果该函数被调用肯定会停下来。}Test(inta){printf(重载%d\n,a);}Test(inta,intb){printf(重载%d\n,ab);}};intmain(){Test te;system(pause);return0;}运行结果这已经证明了Test te;平常这样定义对象的时候调用的是无参构造。如果需要调用有参构造必须传入参数这个特点很简单、有参函数肯定要传参嘛所以定义对象的时候肯定要传入参数啊但是这里建议无论什么时候写类最好还是写上无参构造哪怕什么都不做也尽量写上避免不必要的麻烦。构造函数的作用一般用于初始化类的成员如下12345678910111213141516171819202122232425#include stdio.h#include Windows.hstructTest{intx;inty;intz;Test(){}Test(intx,inty,intz)// 构造函数初始化对象{this-x x;this-y y;this-z z;}};intmain(){Test te;Test te1(1,2,3);// 定义对象并调用有参构造进行初始化printf(%d %d %d\n,te1.x,te1.y,te1.z);// 输出看看是否初始化成功system(pause);return0;}运行如下初始化成功。二、类的析构函数什么是析构函数类的构造函数名前加上~这个符号就是类的析构函数概念模糊、代码如下12345678910111213141516171819#include stdio.h#include Windows.hstructTest{Test(){printf(你调用了一次类的构造函数\n);}~Test(){printf(你调用了一次类的析构函数\n);}};intmain(){Test te;// system(pause); // 这里就不要让程序停下来了不然析构不了return0;}~Test(){}就这个样子析构函数的特点依然直接先来说特点然后论证1、析构函数不能重载、不能有参数2、析构函数在变量声明周期结束时被调用3、析构函数被调用分两种情况堆栈中定义的对象、全局区中定义的对象证明1析构函数不能重载、不能有参数编译不通过。既然不能有参数那重载更不可能了证明成功。证明2析构函数在变量声明周期结束时被调用局部变量的生命周期是在一个大括号内即一个所处块结束。所以1234567891011121314151617181920212223#include stdio.h#include Windows.hstructTest{Test(){printf(你调用了一次类的构造函数\n);}~Test(){printf(你调用了一次类的析构函数\n);}};intmain(){{Test te;printf(te生命周期即将结束。\n);}// 析构应该在这里被调用printf(te生命周期结束。\n);system(pause);return0;}运行结果如下断点结果证明成功。证明3析构函数被调用分两种情况堆栈中定义的对象、全局区中定义的对象已知堆栈中定义的对象局部变量在块语句结束之后就会被调用那么带有return的main函数是在返回前调用析构还是返回后呢代码如下12345678910111213141516171819#include stdio.h#include Windows.hstructTest{Test(){printf(你调用了一次类的构造函数\n);}~Test(){printf(你调用了一次类的析构函数\n);// 断点--汇编}};intmain(){Test te;// system(pause); // 不要使用pause不然无法返回return0;}断点-调试-汇编可以看到是在函数返回前被调用的。如果在全局区定义的对象呢这个问题很难说像我一样定义两个断点就行了如下12345678910111213141516171819#include stdio.h#include Windows.hstructTest{Test(){printf(你调用了一次类的构造函数\n);}~Test()// 断点{printf(你调用了一次类的析构函数\n);}};Test te;intmain(){// system(pause); // 不要使用pause不然无法返回return0;// 断点}运行发现一运行就断在了return当我们发F10继续运行的时候并没有直接调用析构而是到了括号那里继续F10通过翻译可以得知这就是进程结束时的一些收尾工作。继续F10现在大概可以总结了类的对象定义为全局变量时是在main函数结束之后进程退出之前调用的析构函数。小结当类的对象定义为局部变量时堆栈定义这个对象的块作用域结束时就会调用该对象的析构函数如果在main函数这个块作用域中定义的对象那么就是在return之前调用析构。当类的对象定义为全局变量时全局区会在main函数return函数返回之后和进程结束之前调用该对象的析构函数。析构函数的作用我们知道了析构函数都是在类的对象生命周期结束时被调用那么就代表下面不会再使用到这个对象所以析构函数一般用于一些收尾的工作以防忘记。比如当你使用了该对象的成员申请了内存(malloc、new等)、或者open了一些文件那么可以在析构函数中free delete 或者close。例如123456789101112131415161718192021222324#include stdio.h#include Windows.hstructTest{intx;char* name;Test(){name (char*)malloc(sizeof(char)*20);// 构造时动态申请}~Test(){if(this-name!0)// 析构时判断是个否为空不为空释放{free(name);name 0;}}};intmain(){Test te;return0;}复制讲解这里我就不运行了大家可以自己测试下。总结构造函数1、和类具有相同名称并且没有返回值类型的函数就是类的构造函数2、构造函数在定义对象的时候被调用3、构造函数可以进行函数重载可以有很多个4、创建对象时默认调用的是无参构造析构函数1、类的构造函数名前加上~这个符号就是类的析构函数2、析构函数不能重载、不能有参数3、析构函数在变量声明周期结束时被调用4、析构函数被调用分两种情况堆栈中定义的对象、全局区中定义的对象