c++之对象构造顺序和销毁(析构函数)
一、对象的构造顺序:
1、对于局部对象:
当程序执行流到达对象的定义语句时进行构造。下面还是用代码来解析这句话:
#include <stdio.h>
class Test
{
private:
int mi;
public:
Test(int i)
{
mi=i;
printf("Test(int i) is %d",mi);
}
Test(const Test& obj)
{
mi=obj.mi;
printf("Test(const Test&) obj is %d",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 0
Test(int i) is 1
Test(int i) is 2
Test(int i) is 3
Test(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",mi);
}
Test(const Test& obj)
{
mi=obj.mi;
printf("Test(const Test& obj is %d",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 0
Test(int i) is 1
Test(int i) is 2
Test(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",mi);
}
Test(const Test& obj)
{
mi=obj.mi;
printf("Test(const Test& obj is %d",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",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", mi);
}
Test(const Test& obj)
{
mi = obj.mi;
printf("Test(const Test& obj): %d", 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): 0
Test(int i): 1
Test(int i): 3
Test(int i): 5
Test(int i): 7
Test(int i): 9
Test(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", s);
}
};
#endif
最后输出结果:
root@txp-virtual-machine:/home/txp# g++ test1.cpp test2.cpp test3.cpp test4.cpp -o put
root@txp-virtual-machine:/home/txp# ./put
t4
t1
t2
t3
t5
4、小结:
局部对象的构造顺序依赖程序的执行流
堆对象的构造顺序依赖于new的使用顺序
全局对象的构造顺序是不确定的
二、析构函数:
1、c++的类中可以定义一个特殊的清理函数,叫做析构函数,这个函数的功能与构造函数相反,顾名思义就是销毁的意思了。
2、定义:~ClassName()
析构函数没有参数也没有返回值类型声明
析构函数在对象销毁时自动被调用
代码示例:
#include <stdio.h>
class Test
{
int mi;
public:
Test(int i)
{
mi = i;
printf("Test(): %d", mi);
}
~Test()
{
printf("~Test(): %d", mi);
}
};
int main()
{
Test t(1);
Test* pt = new Test(2);
delete pt;
return 0;
}
输出结果:
Test(): 1
Test(): 2
~Test(): 2
~Test(): 1
3、析构函数的定义准则:
当类中自定义了构造函数,并且析构函数中使用了系统资源(比如说,内存的申请,文件打开),那么就需要自定义析构函数了。
4、小结:
析构函数是对象销毁时进行处理的特殊函数
析构函数在对象销毁时自动被调用
析构函数是对象释放系统资源的保障
图片新闻
技术文库
最新活动更多
-
即日-12.26立即报名>>> 【在线会议】村田用于AR/VR设计开发解决方案
-
1月8日火热报名中>> Allegro助力汽车电气化和底盘解决方案优化在线研讨会
-
1月9日立即预约>>> 【直播】ADI电能计量方案:新一代直流表、EV充电器和S级电能表
-
即日-1.14火热报名中>> OFweek2025中国智造CIO在线峰会
-
即日-1.20限时下载>>> 爱德克(IDEC)设备及工业现场安全解决方案
-
即日-1.24立即参与>>> 【限时免费】安森美:Treo 平台带来出色的精密模拟
推荐专题
发表评论
请输入评论内容...
请输入评论/评论长度6~500个字
暂无评论
暂无评论