本篇内容介绍了“c++对象构造顺序和析构函数举例分析”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!
一、对象的构造顺序:
1、对于局部对象:
当程序执行流到达对象的定义语句时进行构造。下面还是用代码来解析这句话:
#include <stdio.h>class Test{ private: int mi; public: Test(int i) { mi=i; printf("Test(int i) is %d\n",mi); } Test(const Test& obj) { mi=obj.mi; printf("Test(const Test&) obj is %d\n",mi); }};int main(){ int i = 0 ; Test a1 =i;//Test(int i):0 while(i<3) { Test a2 = ++i;//Test(int i):1,2,3 } if(i<4) { Test a = a1; //Test(const Test& obj is :0 } else { Test a(100); } return 0;}
输出结果:
Test(int i) is 0Test(int i) is 1Test(int i) is 2Test(int i) is 3Test(const Test& obj) is 0
这里我们可以看出当程序流执行到相应的构造对象的那条执行语句时,就会调用构造函数(或者拷贝构造函数)。goto语句想必大家不陌生,但是都害怕这玩意,下面我们加入goto语句看看会产生什么现象:
#include <stdio.h>class Test{private: int mi;public: Test(int i) { mi=i; printf("Test(int i) is %d\n",mi); } Test(const Test& obj) { mi=obj.mi; printf("Test(const Test& obj is %d\n",mi); }};int main(){ int i = 0; //Test(int i) :0 Test a1 = i; while( i <3) { Test a2 = ++i; //Test(int i) :1,2,3 }goto end; if(i <4) { Test a = a1;//Test(const Test&) obj is :0 } else { Test a(100); }end: return 0;}
输出结果:
Test(int i) is 0Test(int i) is 1Test(int i) is 2Test(int i) is 3
从结果我们可以看出从if那条语句就被跳过了,没有执行到,这里这样写的目的是为了引出,当你使用goto语句,把对象给屏蔽了,后面你不能使用这个对象了,不然程序会出现大问题:
#include <stdio.h>class Test{private: int mi;public: Test(int i) { mi=i; printf("Test(int i) is %d\n",mi); } Test(const Test& obj) { mi=obj.mi; printf("Test(const Test& obj is %d\n",mi); } int getMi() { return mi; }};int main(){ int i = 0; //Test(int i) :0 Test a1 = i; while( i <3) { Test a2 = ++i; //Test(int i) :1,2,3 }goto end; Test a(100);end: printf("a.mi is %d\n",a.getMi()); return 0;}
输出结果:
tt.cpp: In function ‘int main()’:tt.cpp:32:1: error: jump to label ‘end’ [-fpermissive] end: ^tt.cpp:30:6: error: from here [-fpermissive] goto end; ^tt.cpp:31:12: error: crosses initialization of ‘Test a’ Test a(100); ^
这里就是上面所说了的,对象被goto语句给屏蔽了,后面就不能使用这个对象来进行操作了。
2、对于堆对象:
当程序执行流到达new语句时创建对象
使用new创建对象将自动触发构造函数的调用
代码演示:
#include <stdio.h>class Test{private: int mi;public: Test(int i) { mi = i; printf("Test(int i): %d\n", mi); } Test(const Test& obj) { mi = obj.mi; printf("Test(const Test& obj): %d\n", mi); } int getMi() { return mi; }};int main(){ int i = 0; Test* a1 = new Test(i); // Test(int i): 0 while( ++i < 10 ) if( i % 2 ) new Test(i); // Test(int i): 1, 3, 5, 7, 9 if( i < 4 ) new Test(*a1); else new Test(100); // Test(int i): 100 return 0;}
输出结果:
Test(int i): 0Test(int i): 1Test(int i): 3Test(int i): 5Test(int i): 7Test(int i): 9Test(int i): 100
3、对于全局对象:
对象的构造顺序是不确定的
不同的编译器使用不同的规则来确定构造顺序。
同样还是来看代码示例,这里我创建了几个文件:tes1.cpp test2.cpp test3.cpp test4.cpp test.h;他们的内容如下:
test1.cpp:
#include "test.h"Test t4("t4");int main(){ Test t5("t5");}
test2.cpp:
#include "test.h"Test t1("t1");
test3.cpp:
#include "test.h"Test t2("t2");
test4.cpp:
#include "test.h"Test t3("t3");
test.h:
#ifndef _TEST_H_#define _TEST_H_#include <stdio.h>class Test{public: Test(const char* s) { printf("%s\n", s); }};#endif
最后输出结果:
root@txp-virtual-machine:/home/txp# g++ test1.cpp test2.cpp test3.cpp test4.cpp -o putroot@txp-virtual-machine:/home/txp# ./putt4t1t2t3t5
4、小结:
局部对象的构造顺序依赖程序的执行流
堆对象的构造顺序依赖于new的使用顺序
全局对象的构造顺序是不确定的
二、析构函数:
1、c++的类中可以定义一个特殊的清理函数,叫做析构函数,这个函数的功能与构造函数相反,顾名思义就是销毁的意思了。
2、定义:~ClassName()
析构函数没有参数也没有返回值类型声明
析构函数在对象销毁时自动被调用
代码示例:
#include <stdio.h>class Test{ int mi;public: Test(int i) { mi = i; printf("Test(): %d\n", mi); } ~Test() { printf("~Test(): %d\n", mi); }};int main(){ Test t(1); Test* pt = new Test(2); delete pt; return 0;}
输出结果:
Test(): 1Test(): 2~Test(): 2~Test(): 1
3、析构函数的定义准则:
当类中自定义了构造函数,并且析构函数中使用了系统资源(比如说,内存的申请,文件打开),那么就需要自定义析构函数了。
“c++对象构造顺序和析构函数举例分析”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注亿速云网站,小编将为大家输出更多高质量的实用文章!
亿速云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。
原文链接:https://my.oschina.net/u/4065875/blog/4468148