你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

c++——对象构造顺序和销毁

[复制链接]
gaosmile 发布时间:2020-8-4 23:01
一、对象的构造顺序:
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 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\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 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\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): 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\n", 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\n", mi);
    }
    ~Test()
    {
        printf("~Test(): %d\n", 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、小结:
  • 析构函数是对象销毁时进行处理的特殊函数
  • 析构函数在对象销毁时自动被调用
  • 析构函数是对象释放系统资源的保障

收藏 评论0 发布时间:2020-8-4 23:01

举报

0个回答

所属标签

STM32团队

意法半导体微控制器和微处理器拥有广泛的产品线,包含低成本的8位单片机和基于ARM® Cortex®-M0、M0+、M3、M4、M33、M7及A7内核并具备丰富外设选择的32位微控制器及微处理器


最新内容

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
微信公众号二维码 微信公众号
手机版二维码 手机版