您现在的位置是:首页 > 文章详情

c++之对象构造顺序和销毁(析构函数)

日期:2020-08-03点击:456

一、对象的构造顺序:

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、小结:

  • 析构函数是对象销毁时进行处理的特殊函数

  • 析构函数在对象销毁时自动被调用

  • 析构函数是对象释放系统资源的保障


另外可以加群交流(这里不希望打广告的进来):




本文分享自微信公众号 - TXP嵌入式(txp1121518wo-)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

原文链接:https://my.oschina.net/u/4065875/blog/4468148
关注公众号

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。

持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。

转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。

文章评论

共有0条评论来说两句吧...

文章二维码

扫描即可查看该文章

点击排行

推荐阅读

最新文章