c++之對象構造順序和銷燬(析構函數)

1、對象的構造順序:c++

一、對於局部對象:web

當程序執行流到達對象的定義語句時進行構造。下面仍是用代碼來解析這句話:微信

#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;
}

輸出結果:url

Test(int i) is 0
Test(int i) is 1
Test(int i) is 2
Test(int i) is 3

從結果咱們能夠看出從if那條語句就被跳過了,沒有執行到,這裏這樣寫的目的是爲了引出,當你使用goto語句,把對象給屏蔽了,後面你不能使用這個對象了,否則程序會出現大問題:spa

#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;
}

輸出結果:.net

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語句給屏蔽了,後面就不能使用這個對象來進行操做了。code

二、對於堆對象:對象

  • 當程序執行流到達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

三、對於全局對象:

  • 對象的構造順序是不肯定的

  • 不一樣的編譯器使用不一樣的規則來肯定構造順序。

一樣仍是來看代碼示例,這裏我建立了幾個文件: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

四、小結:

  • 局部對象的構造順序依賴程序的執行流

  • 堆對象的構造順序依賴於new的使用順序

  • 全局對象的構造順序是不肯定的

2、析構函數:

一、c++的類中能夠定義一個特殊的清理函數,叫作析構函數,這個函數的功能與構造函數相反,顧名思義就是銷燬的意思了。

二、定義:~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

三、析構函數的定義準則:

當類中自定義了構造函數,而且析構函數中使用了系統資源(好比說,內存的申請,文件打開),那麼就須要自定義析構函數了。

四、小結:

  • 析構函數是對象銷燬時進行處理的特殊函數

  • 析構函數在對象銷燬時自動被調用

  • 析構函數是對象釋放系統資源的保障


另外能夠加羣交流(這裏不但願打廣告的進來):




本文分享自微信公衆號 - TXP嵌入式(txp1121518wo-)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索