6 1 物件的構造與析構

2021-07-04 20:07:19 字數 3881 閱讀 3764

• 物件在被建立時就會呼叫其建構函式 ,若在乙個區段中有乙個以上的離開點,則析構函式必須放在每個離開點前

eg:

//析構函式(儘管程式不會執行到這裡,但在物件的生命結束期末尾也會呼叫析構函式)

}

把物件盡可能的放置在使用它的程式區段附近,可以節省非必要的物件產生操作和銷毀操作

• 全域性物件如果有建構函式與析構函式的話,稱這個全域性物件需要靜態初始化操作和記憶體釋放操作

• c++中所有的全域性變數都放置在程式的資料段中,若顯示給定乙個值,則物件以該值作為初值,否則物件所配置到的記憶體內容為0

全域性類物件在編譯器被放置在資料段中且內容為0,建構函式直到程式啟動時才會實施

• 全域性物件的munch策略,實現在程式開始時對全域性物件進行初始化,在程式結束前呼叫物件的析構函式

為每乙個需要靜態初始化的檔案產生乙個_sti()函式,內含必要的構造函式呼叫操作或 inline expansions

在每乙個需要靜態的記憶體釋放操作的檔案中產生乙個_std()函式,內含必要的析構函式的呼叫操作

提供一組執行時庫」munch」函式:

1)乙個_main()函式(用以呼叫可執行檔案中所有的_sti()函式)

2)乙個exit()函式(用以呼叫可執行檔案中所有的_std()函式)

• 收集乙個程式中各個物件的_sti()函式與_std()函式

分析符號**的方法

a) 使用nm列出物件檔案的符號**專案

b) 使用 munch 程式分析符號**中的名稱,搜尋以_sti或_std開頭的名稱

c) 把這些函式名稱加到乙個sti()函式和std()函式的跳離**中,並將這個更**寫到乙個小的 program test 檔案中

d) cc命令被啟用,編譯這個內含**的檔案,重新連線整個可執行檔案

e) _main()函式與exit()函式在各個**上走訪一遍,輪流呼叫每乙個專案

基於特定平台的c++編譯器的情況下,定義不同的目的檔案格式,以支援靜態初始化與記憶體釋放操作

區域性靜態物件的建構函式與虛構函式在程式的生命週期中只會被呼叫一次,儘管其所在函式可能被呼叫多次

• 保護區域性靜態物件的初始化操作(確保在整個生命週期中只執行一次)

• 匯入乙個臨時物件以保護靜態區域性變數的初始化操作

• 第一次處理其所在函式時,該臨時物件被評估為 false,於是靜態區域性物件建構函式被呼叫,然後將臨時物件改為 true,之後再處理該函式時,不會再呼叫靜態區域性物件的建構函式

• 保護區域性靜態物件的析構操作(確保只在程式結束前進行銷毀)

• 有條件的施行靜態區域性物件的建構函式:僅在靜態區域性物件已經被構造了的情況下,才在最後施行析構操作。(可判斷保護建構函式的臨時物件是否為true)

• 乙個問題:不可以在靜態記憶體釋放函式中訪問靜態區域性物件(因為該物件是區域性的)

eg:

const matrix & identity()

該函式將被擴充套件為以下形式:(加入了建構函式保護物件)

static

struct matrix * __0_f3 = 0; //臨時物件

//c++中的引用在c中是以指標來代替的

struct matrix * identity_fv()

該靜態區域性物件的析構函式將在靜態記憶體釋放函式中有條件的呼叫:

char __std__stat_0_c_j()

• 假設有以下陣列定義:

point knots[10];
• 若 point 即沒有定義乙個建構函式也沒有定義乙個析構函式,則該操作的工作與建立乙個「內建型別所組成的陣列」相同,只需要分配足夠記憶體來儲存10個連續的point元素即可

• 若 point 定義了建構函式或析構函式,則建構函式與析構函式必須輪流施行於每乙個元素之上

• cfront 中,使用乙個命名為vec_new()的函式,產生出以類物件構造而成的陣列(該類物件沒有虛基類),用另乙個命名為vec_vnew()的函式來處理內含虛基類的類物件陣列

• 關於vec_new()

• 原型:void * vec_new(

void * array, //陣列起始位址

size_t elem_size, //每乙個類物件的打下

int elem_coutn, //陣列中元素的個數

void (*constructor)(void*), //建構函式的指標

void(*destructor)(void*,char) //析構函式的指標

)• 若array持有的不是陣列的位址,就是0。若是0,則陣列將通過應用程式的 new 運算子,動態配置於對中。

• eg:上述 point 陣列的定義操作,被編譯器轉換為:

point knots[10];

vec_new(&knots,sizeof(point),10,&point::point,0);

• 當物件陣列的生命結束時,其析構函式也必須實行於每個物件上,此時類似的 vec_delete()與vec_vdelete()函式來完成析構函式的呼叫

• 當程式設計師提供乙個或多個明顯的初值給乙個由類物件組成的陣列時,對於明顯獲得初始的元素,vec_new()不再必要,對未獲得初始值的元素,仍舊呼叫vec_new()

eg:

point knots[10] = ;
編譯器將其轉換為如下:

point knots[10];

//顯示的初始化前三個元素

point::point(&knots[0]);

point::point(&knots[1],1.0,1.0,0.5);

point::point(&knots[2],-1,0,0);

//仍舊以 vec_new() 呼叫建構函式初始化後七個元素

vec_new(&knots+3,sizeof(point),7,&point::point,0);

• 不能在程式中取出建構函式的位址,對vec_new()函式而言,經由乙個指標來啟動建構函式,將無法訪問預設引數值

• cfront的解決辦法:產生乙個內部的stub constructor,該建構函式沒有引數。但在其內部呼叫由程式設計師提供的建構函式,並將引數值顯示的指定過去

• 對於cfront而言,將有兩個沒有引數的建構函式,乙個預設建構函式(帶預設引數值),乙個合成的stub constructor。當時只有當類物件陣列真正被產生出來時,stub例項才會被產生並呼叫

eg:

class

complex

;

當程式設計師定義:complex c_array[10];

編譯器需要呼叫: vec_new(&c_array,sizeof(complex),10,&complex::complex,0); //將無法獲得預設引數

因此,合成以下 stub constructor

complex::complex()

類和物件(3) 物件的構造和析構

如果不用建構函式初始化,該怎麼辦 為每個類都提供乙個public的initialize函式 物件建立後立即呼叫initialize函式進行初始化。缺點1 initialize只是乙個普通的函式,必須顯示的呼叫 2 一旦由於失誤的原因,物件沒有初始化,那麼結果將是不確定的 沒有初始化的物件,其內部成員...

C (16)物件的構造和析構

定義 1 c 中的類可以定義與類名相同的特殊成員函式,這種與類名相同的成員函式叫做建構函式 2 建構函式在定義時可以有引數 3 沒有任何返回型別的宣告。呼叫 自動呼叫 一般情況下c 編譯器會自動呼叫建構函式 手動呼叫 在一些情況下則需要手工呼叫建構函式 定義 1 c 中的類可以定義乙個特殊的成員函式...

物件的構造與析構

建立乙個物件時,常常需要作某些初始化的工作,例如對資料成員賦初值。注意,類的資料成員是不能在宣告類時初始化的。原因 類相當於乙個模板,是一種新資料型別,而非變數,當程式宣告乙個類,未申 請儲存空間,只有當這個類定義物件時才申請空間為了解決這個問題,c 編譯器提供了建構函式 constructor 來...