物件和類 物件的構造

2021-08-20 08:15:36 字數 4167 閱讀 4655

多種型別的建構函式

問題:物件中成員變數的初始值是多少?

示例**:成員變數的初始值

#include 

class test

int getj()

};test gt;

int main()

輸出結果:

gt.i = 0

gt.j = 0

t1.i = 14998400

t1.j = 134514203

pt->i = 0

pt->j = 0

分析:

從程式設計的角度來看,物件也只是變數的一種。根據c語言變數的儲存方式,我們也可以推測得出

1. test gt; 是全域性變數,也就是在靜態儲存區建立物件時,成員變數初始為0值。

2. test t1; 是區域性變數,也就是在棧上建立物件時,成員變數初始為隨機值

3. test t2; 是在堆空間申請的變數,成員變數初始為隨機值

c語言的解決方案

一般而言,我們在c語言是如何初始化結構體裡的變數的呢?

就是專門寫乙個函式,在函式體裡對結構體內的成員進行初始化。

根據c語言的方法,我們可以在類中提供乙個初始化函式

那麼我們在c++類中也可以提供乙個初始化函式,專門將成員變數進行初始化。

但是這種方式也有缺陷:每次定義乙個物件,我們就需要呼叫這個初始化函式。一旦我們忘記呼叫這個初始化函式,導致執行結果是不確定的。

c++建構函式解決成員變數初始化問題

為了解決上面的問題。c++提供了乙個與類名相同的特殊成員函式,這個特殊的成員函式叫做建構函式。

1. 建構函式沒有任何返回型別的宣告

2. 建構函式在物件定義時自動被呼叫

示例**:建構函式初探

#include 

class test

int getj()

test()

};test gt;

int main()

輸出結果:

test() begin

test() end

gt.i = 1

gt.j = 2

test() begin

test() end

t1.i = 1

t1.j = 2

test() begin

test() end

pt->i = 1

pt->j = 2

分析:

1. 在程式中,我們可以看出,建構函式在物件定義時自動被呼叫

2. 類的建構函式用於物件的初始化

3. 建構函式與類同名並且沒有返回值

我們上面介紹的建構函式也有缺陷的。因為除了定義類的物件如何初始化之外,類還需要控制拷貝、賦值和銷毀物件時發生的行為。

那麼我們如何讓建構函式能適應各種各樣的場合呢?

1. 類物件直接的賦值

2. 建構函式可以根據需要定義引數

帶引數的建構函式

因為當我們需要建立多個物件時,每個物件的成員變數的初始值都是一樣的。這樣並不能適用一些特定的情況。

示例**:帶引數的建構函式

#include 

class test

test(int v)

};int main()

輸出結果:

test()

test(int v), v = 1

test(int v), v = 2

test(int v), v = 3

i = 100

分析:

1. 乙個類中可以存在多個建構函式,前提是引數個數和引數型別不同(基於函式過載規則)

2. 建構函式的初始化與普通變數的初始化一樣。(構造函式引數有多少個,初始化引數也必須有多少個)

3. 當沒有定義任何建構函式時,編譯器才會提供預設建構函式。所以當我們定義了帶有引數的建構函式時,必須為它提供乙個預設建構函式,否則編譯出錯。

拷貝建構函式

對於普通型別的物件來說,他們之間的複製是很簡單的,例如:

int a = 100;

int b = a;

問題:那麼我們類物件也可以像普通物件一樣,直接將類物件的值拷貝過去嗎?

示例**:類物件拷貝的簡單例子

#include 

class test

int geti()

int getj()

};int main()

輸出結果:

t1.i = 1, t1.j = 2

t2.i = 1, t2.j = 2

分析:

系統是如何給test 物件裡的成員函式對應拷貝的呢?如何準確的吧各個成員變數進行拷貝的呢?

實際上,編譯器會我們提供乙個拷貝建構函式來完成整個複製了

問題:編譯器為我們提供的拷貝建構函式並不能完全滿足我們的工作需求,那麼我們如何顯示定義拷貝建構函式呢?

示例**:自定義拷貝建構函式

//在上面**的類成員中,加入下面**即可

test(const test& t)

test(const test& t)就是我們自定義的拷貝建構函式。

可見,拷貝建構函式是一種特殊的建構函式,函式名稱必須和類名相同,它的引數必須是本型別的乙個引用變數

實際上,我們自定義的拷貝建構函式可以選擇哪些引數需要拷貝,哪些引數不拷貝。

注意:在程式設計中我們盡量要使用自定義拷貝函式,不僅可以選擇需要拷貝的類成員,也可以阻止編譯器形成預設的拷貝建構函式

淺拷貝(拷貝建構函式資源衝突)

問題:當類中有指標成員時,使用預設拷貝建構函式會有什麼問題嗎?

示例**:帶指標成員的拷貝建構函式

#include 

class test

int getj()

int* getp()

test(int v)

void free()

};int main()

輸出結果:

t1.i = 1, t1.j = 2, *t1.p = 0x871f008

t2.i = 1, t2.j = 2, *t2.p = 0x871f008

* glibc detected./a.out: double free or corruption (fasttop): 0x0871f008 **

//後面還有一大串資料,關於記憶體的

分析:

1. 從輸出結果可以知道:當類中有指標成員時,使用系統預設建立該拷貝建構函式會出現記憶體操作錯誤。

2. 從t1.getp()和t2.getp()列印資料可以知道:指標指向位址是相同的,都是0x871f008。所以當後面我們free()釋放記憶體時,就會出現記憶體重複釋放的情況。導致執行出錯。

c++對於這種情況解析為:淺拷貝,也就是說拷貝後物件的物理狀態相同(共用乙個資源)。所以編譯器提供的拷貝建構函式只進行淺拷貝。

深拷貝(解決建構函式資源問題)

問題:我們如何解決淺拷貝造成的問題?

依然是自定義拷貝建構函式,在拷貝構造裡需要重新申請資源。

示例**:淺拷貝的解決方案

//新增這段**到上面**的類中即可

test(const test& t)

深拷貝的應用場景

物件中有成員指代了系統中的資源

成員指向了動態記憶體空間

成員開啟了外存中的檔案

成員使用了系統中的網路埠

類和物件 複製建構函式

形如x x x 或x x const x 二選一,後者能以常量物件作為引數 class complex complex c1 呼叫預設無參建構函式 complex c2 c1 呼叫預設的複製建構函式,將 c2 初始化成和c1一樣class complex complex const complex ...

C C 類和物件 物件移動和移動建構函式

c 11引入物件移動 進行所有權的轉移 移動建構函式和移動賦值運算子應該完成的功能 引入目的 提高程式效率 說明 a b,那麼a物件就不能再使用了 拷貝建構函式 class temp temp temp const temp tmp 引數是const左值引用移動建構函式 class temp tem...

類和物件 物件特性 構造函式呼叫規則

預設情況下,c 編譯器至少給乙個類新增三個函式 預設建構函式 無參,函式體為空 預設析構函式 無參,函式體為空 預設拷貝建構函式,對屬性進行值拷貝 構造函式呼叫規則如下 include using namespace std 按照引數分類 有參構造 預設構造 無參構造 按照型別分類 普通構造 拷貝構...