c 的初始化與清除

2021-07-10 06:08:18 字數 2915 閱讀 4664

第4章 初始化與清除

第2章利用了一些分散的典型c語言庫的構件,並把它們封裝在乙個struct總,從而在庫的應用方面做了有意義的改進(從現在起,這個抽象資料型別稱為類)

1)這樣用類名隱藏了類內部的函式名,並且通過設立處理界限,意味著資料型別的內部機制對設計者來說是可控的和能自行處理的。封裝和實現的隱藏大大地改善了庫的使用。而安全性包括初始化和清除兩個方面。在c語言中,如果乙個程式設計師忘記了初始化或清除乙個變數,就會導致一大段程式錯誤。特別是當使用者不知如何對乙個struct初始化,甚至不知道必須要初始化時。。。清除是乙個特殊的問題,因為c程式設計師一旦用過乙個變數後就把它給忘記了,所以對乙個庫的struct來說,必要的清除工作往往被遺忘了。在c++中,初始化和清除的概念是簡化類庫使用的關鍵所在,並且可以減少那些由於使用者忘記這些操作而引起的許多細微錯誤

2)在c++中,初始化是在太重要了,所以不能把它留給使用者來完成。類的設計者可以通過提供乙個叫做建構函式的特殊函式來保證每個物件都正確地初始化。如果乙個類有建構函式,編譯器在建立物件時就自動呼叫這一函式,這一切在使用者是用他們的物件之前就已經完成了。對使用者來說,是否呼叫建構函式並不是可選的,它是由編譯器在物件定義時完成的。

3)函式名字必須考慮兩點:首先這個名字不能與類的其他成員函式衝突,其次,因為該函式是由編譯器呼叫的,所以編譯器必須總能知道呼叫哪個函式。由此得出:建構函式的名字和類的名字一樣。這使得這樣的函式在初始化時自動被呼叫。

4)像其他函式一樣,我們也可以通過建構函式傳遞引數,指定物件該如何建立,設定物件的初始值等等。建構函式的引數保證物件的所有部分都被初始化成合適的值。

5)小結:建構函式是乙個有著特殊名字,有編譯器自動為每個物件呼叫的函式然而它解決了類的很多問題,並使得**更容易閱讀,比如在c中我們可能要設乙個函式initialize(),這些函式從概念上說是與定義分開了。在c++中,定義和初始化時同一概念,不能只取其中之一。

6)建構函式和析構函式是兩個非常特殊的函式:它們沒有返回值。這與返回值為void的函式顯然不同。後者雖然也不返回任何值,但是我們還可以讓它做點別的。而建構函式和析構函式則不允許。在程式中建立和消除乙個物件的行為非常特殊,就像出生和死亡,而且總是由編譯器來呼叫這些函式以確保它們被執行。如果它們有返回值,要麼編譯器必須知道如何處理返回值,要麼就只能有使用者自己來顯示地呼叫建構函式和析構函式,這樣一來,安全性就被破壞了。

7)用析構函式來確保清除

作為乙個c程式設計師,我們可能會經常想到要初始化的重要性,但很少想到清除的重要性。畢竟清除乙個整形變數時需要作什麼?只需要忘記它。然而,在乙個庫中,對於乙個曾經使用過的物件,僅僅「忘記它」是不安全的。如果我們只是「忘記它」,我們的物件就永遠不會消失,在c++中,清除就和初始化一樣重要。通過析構函式來保證清除的執行。

8)析構函式的語法和建構函式一樣,用類的名字做函式名,再在前面加上乙個~,以和建構函式區別。另外,析構函式不帶任何引數,因為析構不需要任何選項。當物件超出它的定義範圍時,編譯器自動呼叫析構函式。我們知道,在物件的定義點出建構函式被呼叫,但西溝函式呼叫的唯一根據是包含該物件的右括號。舉個例子來表示:

// 標頭檔案

#ifndef destructors_h

#define destructors_h

class tree ;

#endif

//實現函式

#include

#include

tree::tree(int initialheight)

tree::~tree() 好了

puts("inside tree destructor");

printsize();

}void tree::grow(int years)

void tree::printsize()

// 測試函式

#include

#include

int main()

puts("after closing brace");

return

0;}

執行結果是:

before opening brace

after tree creation

tree height is 12

before closing brace

inside tree destructor

tree height is 16

after closing brace

9)在c中,我們總要在乙個程式塊的左括號一開始就定義好所有的變數,這在程式語言中並不少見(pascal中除外),其理由無非是「這是乙個好的程式設計風格」,但是作為程式設計師,如果需要增加乙個變數時總得調到塊的開始;而如果變數定義緊靠著變數的使用處是,程式的可讀性更強。

10)在c++中,如果在一開始就要把所有的物件定義出來,我們不一定會在所有物件開始定義是知道它們的初始化資訊。這樣很容易將定義與初始化的部分分開,然而c++要保證在乙個物件產生時,它同時被初始化。這樣可以保證我們的系統中沒有為初始化的物件。

通常,在c++中,在還不擁有建構函式的初始化資訊是不能建立乙個物件,所以不必在塊的開頭定義所有的變數這也意味著我們可以等到我們已經知道乙個變數的必要資訊時再去定義它,所以我們總是可以同時定義和初始化乙個變數。而且我們也應該這樣去做。

11)因為物件的建構函式與析構函式都是自動呼叫的,所以類的使用者只要把精力集中於怎樣使用這些物件上,而不需要擔心它們是否已被正確地初始化和清除了

小結:因為建構函式與析構函式讓我們保證正確地初始化和清除物件(編譯器不允許沒有呼叫構造寒素與析構函式就直接建立與銷毀乙個物件),是我們得到了完全的控制與安全。

編碼期間的安全性是c++中的一大問題,初始化和清除是這其中的乙個重要部分,隨著本書的進展,我們可以看到其他的安全性問題。

c 直接初始化與拷貝初始化

我們常見的幾種初始化的形式 string str1 first 拷貝初始化,編譯器允許把這句話改寫為string str first 但是string類必須有public的拷貝 移動 建構函式 string str2 10,a 直接初始化 string str3 str2 直接初始化 string ...

Thinking in C 5 初始化與清除

class y當物件超出它的作用域時,編譯器會自動呼叫析構函式。如下述例子所示 class tree tree tree int inittialheight tree tree void tree grow int years void tree printsize intmain 在此處編譯器自...

第6章 初始化與清除

用建構函式確保初始化 在乙個物件被定義時 x a 這時就好像a 是乙個int 一樣 為這個物件分配記憶體。但是當程式執行到 a的序列點執行的點時,建構函式自動被呼叫,因為編譯器已悄悄地在 a的定義點處插入了乙個 x x 的呼叫。就像其他成員函式被呼叫一樣。傳遞到建構函式的第乙個 秘密 引數是 thi...