建構函式與析構函式

2021-10-05 19:33:29 字數 4626 閱讀 5285

當宣告乙個類物件時, 編譯程式需要為物件分配儲存空間, 進行必要的初始化, 這部分工作隨著類的不同而不同。在 c + + 中, 由建構函式來完成這些工作。建構函式是屬於某乙個類的,它可以由使用者提供, 也可以由系統自動生成。與建構函式對應的是析構函式, 當撤消類物件時, 析構函式就**儲存空間,並做一些善後工作。析構函式也屬於某乙個類, 它可以由使用者提供, 也可以由系統自動生成。

建構函式是一種特殊的成員函式,它主要用於為物件分配空間, 進行初始化。建構函式具有一些特殊的性質:

建構函式的名字必須與類名相同。

建構函式可以有任意型別的引數, 但不能具有返回型別

定義物件時, 編譯系統會自動地呼叫建構函式

下面我們為類 complex 建立乙個建構函式。

class

complex

double

abscomplex()

};

上面宣告的類名為 complex, 其建構函式名也是 complex。建構函式的主要功能是對物件進行初始化,即對資料成員賦初值。這些資料成員通常為私有成員。建構函式很少做賦初值以外的事情。

建構函式不能像其它成員函式那樣被顯式地呼叫,它是在定義物件的同時呼叫的, 其一般格式為:

類名 物件名(實參表)

;

說明:

建構函式的名字必須與類名相同, 否則編譯程式將把它當作一般的成員函式來 處理。

建構函式沒有返回值, 在宣告和定義建構函式時, 是不能說明它的型別的,甚至 說明為 void 型別也不行。

在實際應用中, 通常需要給每個類定義建構函式。如果沒有給類定義建構函式, 則編譯系統自動地生成乙個預設的建構函式。例如,編譯系統為類 complex 生成下述形 式的建構函式:

complex∷complex()

建構函式可以是不帶引數的

建構函式也可採用構造初始化表對資料成員進行初始化, 這是某些程式設計師喜歡使用的方法。

classa}

;

但是如果需要將資料成員存放在堆中或陣列中,則應在建構函式中使用賦值語句, 即使建構函式有初始化表也應如此,例如:

class

x;

注意:在這個類的建構函式中, 構造初始化表初始化了三個非陣列成員, 而字元陣列必須在函式體內被賦值。

對沒有定義建構函式的類, 其公有資料成員可以用初始值表進行初始化。

#include

class

myclass

;void

main()

; cout << a.name <<

" "<< a.no << endl;

}

對於帶引數的建構函式,在定義物件時必須給建構函式傳遞引數, 否則建構函式將不被執行。但在實際使用中,有些建構函式的引數值通常是不變的, 只有在特殊情況下才需要改變它的引數值,這時可以將其定義成帶預設引數的建構函式, 例如:

class

complex

;complex∷complex

(double r,

double i)

double complex∷abscomplex()

在類 complex 中, 建構函式 complex( )的兩個引數均含有預設引數值 0 .0。因此, 在定義物件時可根據需要使用其預設值。

下面我們用 main( )函式來使用它:

main (

)

在上面定義了三個物件 s1、s2 和 s3, 它們都是合法的物件。由於傳遞引數的個數不同,使它們的私有資料成員 real 和 imag 取得不同的值。由於定義物件 s1 時,沒有傳遞數,所以 real 和 imag 均取建構函式的預設值為其賦值, 因此 real 和 imag 均為 0.0。在定義物件 s2 時, 只傳遞了乙個引數,這個引數傳遞給建構函式的第乙個參量, 而第二個參量取預設值, 所以物件 s2 的 real 取值為 1 .1, 而 imag 取值為 0 .0。在定義物件 s3 時, 傳遞了兩個引數,這兩個引數分別傳給了 real 和 imag,因此 real 取值為 1 .1, imag 取值為 2 .2。

析構函式也是一種特殊的成員函式。它執行與建構函式相反的操作, 通常用於執行一些清理任務,如釋放分配給物件的記憶體空間等。析構函式有以下一些特點:

析構函式與建構函式名字相同, 但它前面必須加乙個波浪號(~)

析構函式沒有引數, 也沒有返回值, 而且不能過載, 因此在乙個類中只能有乙個析構函式。

當撤消物件時, 編譯系統會自動地呼叫析構函式

下面我們重新說明 complex 類, 使它既含有建構函式,又含有析構函式。

#include

#include

using

namespace std;

class

test

;test::

test

(double r ,

double i )

//定義建構函式

test::

~test()

//定義析構函式

double test::

abstest()

intmain()

在類 complex 中定義了建構函式和析構函式。由於類 complex 較為簡單, 物件撤消時不需要什麼特殊的清理工作,因此我們讓析構函式只輸出乙個串「destructing…」。程式

執行結果如下:

constructing…

abs of complex a = 2 .459675

destructing…

**說明:**每個類必須有乙個析構函式。若沒有顯式地為乙個類定義析構函式, 編譯系統會自動地生成乙個預設的析構函式。例如, 編譯系統為類 complex 生成預設的建構函式

complex∷

~complex (

)

對於大多數類而言,預設的析構函式就能滿足要求。但是, 如果在乙個物件完成其操作之前需要做一些內部處理,則應該顯式地定義析構函式, 例如:

class

string

- data

~string -

data()

void get -

info

(char*)

;void sent -

info

(char*)

;};

這是建構函式和析構函式常見的用法,即在建構函式中用運算子 new 為字串分配儲存空間,最後在析構函式中用運算子 delete 釋放已分配的儲存空間。

在過載沒有引數和帶預設引數的建構函式時, 有可能產生二義性,例如:

classx;

intmain()

該例定義了兩個過載建構函式 x, 其中乙個沒有引數, 另乙個帶有乙個預設引數。建立物件 two 時, 由於沒有給出引數,它既可以呼叫第乙個建構函式, 也可以呼叫第二個建構函式。這時,編譯系統無法確定應該呼叫哪乙個建構函式, 因此產生了二義性。在實際應用時,一定要注意避免這種情況。

拷貝建構函式是一種特殊的建構函式。它用於依據已存在的物件建立乙個新物件。典型的情況是,將引數代表的物件逐域拷貝到新建立的物件中。

使用者可以根據自己的需要定義拷貝建構函式,系統也可以為類產生乙個預設的拷貝建構函式。

1 . 自定義拷貝建構函式

自定義拷貝建構函式的一般形式如下:

classname (

const classname &ob)

其中,ob 是用來初始化另乙個物件的物件的引用。

下面是乙個使用者自定義的拷貝建構函式:

#include

using

namespace std;

class

point

point

(const point &p)

// 拷貝建構函式

void

print()

};int main (

)

假如 p1、p2 為類 point 的兩個物件,且 p1 已經存在, 則下述語句可以呼叫拷貝建構函式初始化 p2:

point p2

( p1 )

;

本例除了顯式呼叫拷貝建構函式外, 還可以採用賦值形式呼叫拷貝建構函式。例如

main (

)

在定義物件 p2 時, 雖然從形式上看是將物件 p1 賦值給了物件 p2, 但實際上呼叫的是拷貝建構函式, 在物件 p2 被建立 時, 將物件 p1 的值逐域 拷貝給對 象 p2, 執行結 果同上。

2 . 預設的拷貝建構函式

如果沒有編寫自定義的拷貝建構函式, c + + 會自動地將乙個已存在的物件複製給新物件,這種按成員逐一複製的過程是由預設拷貝建構函式自動完成的。

說明:

與一般的建構函式一樣, 拷貝建構函式沒有返回值

通常預設的拷貝建構函式是能夠勝任工作的, 但若類中有指標型別時, 按成員復 制的方法有時會產生錯誤。

建構函式與析構函式

建構函式 主要作用就是為物件初始化。有一點要說的是,在繼承體系彙總,如果在建構函式中,如果沒有指定基類的建構函式,那麼編譯器會在建構函式開頭加入,基類的預設建構函式,這樣就可以初始化基類物件部分 析構函式 對於析構函式,要說的多點,實際也不太複雜,就是加入了virtual 使其具有了多型性質 inc...

建構函式與析構函式

建構函式 先看看建構函式的呼叫順序規則,只要我們在平時程式設計的時候遵守這種約定,任何關於建構函式的呼叫問題都能解決 建構函式的呼叫順序總是如下 1.基類建構函式。如果有多個基類,則建構函式的呼叫順序是某類在類派生表中出現的順序,而不是它們在成員初始化表中的順序。2.成員類物件建構函式。如果有多個成...

建構函式與析構函式

概述 乙個類有兩種特殊的成員函式 建構函式與析構函式。建構函式功能是在建立物件時,給資料成員賦初值,即物件的初始化。析構函式的功能是釋放乙個物件,在物件刪除前,用它做一些記憶體釋放工作,與建構函式的功能相反。建構函式 在物件建立時它會被自動執行,因此變數 物件的初始化 一般都放在建構函式中。1 物件...