C 函式高階功能之類和動態記憶體分配

2021-10-08 18:53:23 字數 3475 閱讀 6147

3. 關於返回物件的說明

4. 使用指向物件的指標

5. 轉換函式

以下未標註的都是c++特有的功能

如果在類中定義了乙個statics int a;那麼無論建立多少個物件,都只共享乙個靜態成員a,這在所有類物件具有相同值的私有資料,這一應用場合是十分有用的。

對於以下五種函式,如果程式設計師不提供,編譯器會自動提供。

預設建構函式

預設析構函式

複製建構函式

賦值運算子

位址運算子

對於編譯器提供的預設析構函式,編譯器不會進行任何操作。對於編譯器提供的位址運算子,會返回this指標,即呼叫物件的位址,這與我們的初衷是一致的。下面著重對函式,3,4進行討論。

如果程式設計師不提供任何建構函式,編譯器會提供乙個預設建構函式,這個函式不接受任何的引數,不返回任何的引數,不執行任何的操作。比如對於類test,那麼編譯器會提供:

test::

test()

//如果在主函式有以下宣告,那麼a相當於乙個初始值未知的類,相當於int a,這個a的值是多少並不知道。

test a;

如果想要在定義的時候就初始化,那麼可以顯式地定義乙個預設建構函式,即:

test::

test

(const

int a =1)

複製建構函式的作用是將乙個物件複製新建立的物件,這也就意味著,這個函式是在初始化的時候呼叫,而不是常規的賦值過程呼叫。

這個函式的原型通常如下:

class_name

(const class_name &

);

在定義的時候:

class_name::

class_name

(const class_name &

);

以下的四種宣告都會呼叫複製建構函式,他們的本質特點都是在新建乙個物件的時候將其初始化為乙個已有物件(這個本質特點也就意味著按值傳遞物件和返回物件時都會呼叫複製建構函式)。

stringbad bill

(tom)

;stringbad bill = tom;

stringbad bill =

stringbad

(tom)

;stringbad *ptrtobill =

newstringbad

(tom)

;//這個的意思是新建乙個物件初始化為tom,然後把新建物件的位址傳給ptrtobill

編譯器提供的隱式複製建構函式是一種淺複製,即按值複製,如果不涉及到指標和引用,就沒關係,如果涉及到指標和引用,那麼淺複製會讓兩個不同的物件指向同一位址,這在析構的時候會引發錯誤。

此時最好定義乙個顯式的複製建構函式,來避免這個災難。就是在程式設計師自己定義的複製建構函式中,申請記憶體空間,將值複製到這個新的記憶體空間中,這樣兩個物件不會指向同一位址,但是位址的內容相同,這就是深複製

賦值運算子的作用是將乙個已有物件複製另乙個已有物件,這也就意味著是常規的賦值過程呼叫。

這個函式的原型通常如下:

class_name&

operator=(

const class_name &

);

在定義的時候

class_name& class_name::

operator=(

const class_name &

);

編譯器提供的隱式賦值運算子問題也在於是一種淺複製,一旦涉及到指標或者引用的話,需要程式設計師自己編寫乙個深複製的賦值運算子,以進行過載。當然,這個實現的細節要用delete先把之前的指標指向的記憶體釋放掉,重新給乙個記憶體空間,然後再進行深度複製,這樣做的目的是為了防止之前的空間不足,比如之前是給了10個字元的空間,但是之後賦值需要15個字元的空間,所以需要重新分配空間,防止陣列訪問越界。

注意運算子(=)只能用成員函式過載,不能用友元過載

例如在函式定義中:

const test & test::

compare

(const test&a1,

const test&a2)

顯然這種方式需要這幾點:

返回引用物件必須是傳入的引用引數,因為在函式內的變數都是臨時變數,一旦函式結束,記憶體全被釋放掉了。

傳入的引數也是const變數,當然不是的話,非const可以強制轉換為const,也沒關係。

顯然這種引用傳遞,效率更高。

這種返回型別的典型案例是過載賦值運算子過載輸出流<<

在過載賦值運算子的時候,需要return *this; 這個通常是用成員函式。return *this的目的是為了使s1 = s2 = s3這種連續賦值能夠成立。

在過載輸出流時,需要return os; 這個通常是用友元函式。

這是在返回的是函式內的變數,即區域性變數時使用。典型應用是算術運算子的過載

這是為了避免一些錯誤的輸入格式。比如對於加法運算子的過載

vector vector::

operator+(

const vector &b)

這樣定義的話,假設有三個vector類的物件a、b、c,那麼a+b = c也不會報錯,但顯然應該要寫為c = a+b。因為在a+b=c的語句中,a+b會先計算,然後呼叫複製建構函式,將結果賦給乙個臨時物件,接著又把物件c賦給這個臨時物件,語句結束後,臨時物件消失,整個過程其實什麼都沒做,但編譯器也不會報錯。

但是如果按照下面的定義:

const vector vector::

operator+(

const vector &b)

那麼a+b=c就會報錯了,因為此時的臨時變數會是乙個const型別,把c賦給const型別是非法的。

比如:

class

vector

int main

指向物件的指標,直接用delete釋放就好了,裡面如果有動態記憶體分配,析構函式會自行處理。

單個值轉換為類的型別,需要如下原型的類建構函式:

c_name (type_name value)

;

operator type_name (

);

注意上面這個函式雖然沒有返回值,但是在函式裡面需要return 對應的type_name型別

C 動態記憶體和動態陣列

全域性物件在程式啟動時分配,在程式結束時銷毀。區域性自動物件,當我們進入其定義所在的程式塊時被建立,在離開塊時銷毀。區域性 static 物件在第一次使用前分配,在程式結束時銷毀 靜態記憶體用來儲存區域性static物件,類static 資料成員,以及定義在任何函式之外的變數。棧記憶體用來儲存定義在...

C動態記憶體開闢函式總結

void malloc size t size malloc 函式向記憶體申請一塊連續的空間,並且返回指向這塊空間的位址。注意,malloc只負責動態開闢一段連續空間,並不負責這塊空間的初始化。void free void ptr free函式是專門用來做動態開闢記憶體的釋放和 int arr 10...

C語言動態記憶體分配函式

目錄 1.malloc 2.free 3.calloc 4.realloc 5.小結 在c中我們開闢記憶體空間有兩種方式 1.靜態開闢記憶體 例如 int a int b 10 這種開闢記憶體空間的特點是 所開闢的記憶體是在棧中開闢的固定大小的 如a是4位元組 陣列b是40位元組 並且陣列在申明時必...