C 中六個預設的函式

2021-09-22 16:40:13 字數 4439 閱讀 6807

c++物件導向特點:繼承、封裝、多型

任務是初始化物件的記憶體空間。

注意:新物件被建立,由編譯器自動呼叫建構函式,且在物件的生命週期之內只調動一次不可以手動呼叫,類的成員方法依賴物件呼叫,即在建構函式完成後;

建構函式的名字和類名相同,沒有返回值

建構函式可以過載,實參決定了呼叫哪個建構函式;沒有顯示定義建構函式,編譯器會提供乙個預設的建構函式

建構函式不能用const來修飾。const可以修飾類的成員函式,但是該函式不能修改資料成員。建構函式也屬於類的成員函式,但是建構函式是要修改類的成員變數、給成員變數做初始化,所以類的建構函式不能申明成const型別的。

建構函式不能用static修飾,因為建構函式只關聯乙個物件而被調動,宣告成static是沒有意義的;

建構函式的初始化列表:初始化列表僅用於初始化資料成員,初始化只能初始化一次,不指定這些成員的初始化順序資料成員在類中的定義順序就是在引數列表中的初始化順序

在建構函式體內可以使用this指標,在初始化列表中不能使用this,因為在初始化列表階段還不知道物件的成員記憶體布局,無法訪問;

預設的建構函式什麼事都不做,使用者提供了,則系統就不會再提供。預設的構造函式呼叫方式:

date d1(); //函式宣告

date d2; //物件生成,呼叫預設的建構函式

在類中包含以下成員,必須要在初始化列表進行初始化:

(1)const修飾的成員變數:const具有常屬性,必須初始化,它不能在別的地方被再次賦值修改。

(2)引用的資料成員:因為引用必須在定義時初始化,且不能重新賦值;

(3)類型別的成員(該類沒有預設的建構函式):因為使用初始化列表不用呼叫預設的建構函式,而是直接使用拷貝建構函式初始化;

當建構函式參數列中並不全部使用預設引數時,具有預設值的引數必須放置於參數列的最後。函式的預設值從右向左依次賦之,自左向右進行實參與形參的匹配

以下:coordinates (int i, int j=100) 的參數列是對的;

coordinates (int i=100, int j) 的參數列是錯的。

對於只有乙個引數的建構函式它預設的具有一種型別轉化的功能——即使用內建型別對自定義型別進行賦值。explicit(顯示的)關鍵字修飾建構函式/拷貝建構函式,禁止隱式生成物件

用explicit修飾建構函式,將會禁止單參建構函式的隱式轉換。

與建構函式功能相反,在物件被銷毀時,由編譯器自動呼叫,釋放物件所佔的資源。

注意:析構函式名:~類名()

析構函式前物件存在,可以手動呼叫,但不建議這樣做。手動呼叫析構函式會退化成普通方法,系統還會呼叫一次析構函式,造成資源再釋放程式崩潰;

預設的析構函式什麼事都不做;

沒有引數、沒有返回值;

乙個類有且只有乙個析構函式。若未顯示定義,系統會自動生成預設的析構函式;

物件生命週期結束時,c++編譯系統系統自動呼叫析構函式;

注意析構函式體內並不是刪除物件,而是做一些清理工作;

不可以過載

用乙個已存在的物件來生成相同型別的新物件

注意:它是建構函式的過載;

以下情況都會呼叫拷貝建構函式:

1.乙個物件以值傳遞的方式傳入函式體或從函式返回

2.乙個物件需要通過另外乙個物件進行初始化。

它的引數必須使用同型別物件的引用傳遞,因為物件以值傳遞的方式進入函式體就會呼叫拷貝建構函式,這樣就會形成無限遞迴導致棧溢位,程式崩潰。

如果沒有顯示定義,系統會自動合成乙個預設的拷貝建構函式,預設的拷貝建構函式會依次拷貝類的資料成員完成初始化。

預設的拷貝建構函式是淺拷貝、有指標型別要考慮深拷貝

如果不去改變實參的值的話,引數不加const的效果和加const的效果是一樣的,而且不加const編譯器也不會報錯,因為函式的形參是引用,則呼叫函式時不需要複製實參,函式是直接訪問呼叫函式中的實參變數的。但是為了整個程式的安全,還是加上const,防止對實參的意外修改

用乙個已存在的物件給另乙個已存在的物件賦值

引數:一般地,賦值運算子過載函式的引數是函式所在類的const型別的引用

加const是因為

(1)防止修改實參的值;

(2)加上const,可以接收隱式生成的臨時量(常量)。對於const的和非const的實參,函式就能接受;如果不加,就只能接受非const的實參。

用引用是因為:這樣可以避免在函式呼叫時對實參的一次拷貝,提高了效率。

返回值一般地,返回值是類型別的引用原因是

(1)這樣在函式返回時避免一次拷貝,提高了效率。

(2)更重要的,這樣可以實現連續賦值,即類似a=b=c這樣。如果不是返回引用而是返回值型別,那麼,執行a=b時,呼叫賦值運算子過載函式,在函式返回時,由於返回的是值型別,所以要對return後邊的「東西」進行一次拷貝,得到乙個未命名的臨時物件,然後將這個副本返回,而這個副本是右值,所以,執行a=b後,得到的是乙個右值,再執行=c就會出錯。

程式沒有顯式地提供乙個以本類或本類的引用為引數的賦值運算子過載函式時,編譯器會自動生成這樣乙個賦值運算子過載函式。注意限定條件,不是說只要程式中有了顯式的賦值運算子過載函式,編譯器就一定不再提供預設的版本,而是說只有程式顯式提供了以本類或本類的引用為引數的賦值運算子過載函式時,編譯器才不會提供預設的版本。

賦值運算子過載函式只能是類的非靜態的成員函式,不能是靜態成員函式,也不能是友元函式。

之所以不是靜態成員函式,是因為靜態成員函式只能操作類的靜態成員,不能操作非靜態成員。如果我們將賦值運算子過載函式定義為靜態成員函式,那麼,該函式將無法操作類的非靜態成員,這顯然是不可行的。

當程式沒有顯式地提供乙個以本類或本類的引用為引數的賦值運算子過載函式時,編譯器會自動提供乙個。現在,假設c++允許將賦值運算子過載函式定義為友元函式並且我們也確實這麼做了,而且以類的引用為引數。與此同時,我們在類內卻沒有顯式提供乙個以本類或本類的引用為引數的賦值運算子過載函式。由於友元函式並不屬於這個類,所以,此時編譯器一看,類內並沒有乙個以本類或本類的引用為引數的賦值運算子過載函式,所以會自動提供乙個。此時,我們再執行類似於str2=str1這樣的**,那麼,編譯器是該執行它提供的預設版本呢,還是執行我們定義的友元函式版本呢?

為了避免這樣的二義性,c++強制規定,賦值運算子過載函式只能定義為類的非靜態成員函式,這樣,編譯器就能夠判定是否要提供預設版本了,也不會再出現二義性。

設計流程:1、判斷自賦值;2、釋放舊資源;3、開闢新資源;4、賦值。

賦值運算子過載函式要避免自賦值

對於賦值運算子過載函式,我們要避免自賦值情況(即自己給自己賦值)的發生,一般地,我們通過比較賦值者與被賦值者的位址是否相同來判斷兩者是否是同一物件(如中的if (this != &rhs)一句)。

為什麼要避免自賦值呢?

(1)為了效率。顯然,自己給自己賦值完全是毫無意義的無用功,特別地,對於基類資料成員間的賦值,還會呼叫基類的賦值運算子過載函式,開銷是很大的。如果我們一旦判定是自賦值,就立即return *this,會避免對其它函式的呼叫。

(2)如果類的資料成員中含有指標,自賦值有時會導致災難性的後果。對於指標間的賦值(注意這裡指的是指標所指內容間的賦值,這裡假設用_p給p賦值),先要將p所指向的空間delete掉(為什麼要這麼做呢?因為指標p所指的空間通常是new來的,如果在為p重新分配空間前沒有將p原來的空間delete掉,會造成記憶體洩露),然後再為p重新分配空間,將_p所指的內容拷貝到p所指的空間。如果是自賦值,那麼p和_p是同一指標,在賦值操作前對p的delete操作,將導致p所指的資料同時被銷毀。那麼重新賦值時,拿什麼來賦?

所以,對於賦值運算子過載函式,一定要先檢查是否是自賦值,如果是,直接return *this。

c 中的六個預設函式

1.c 三大特徵 封裝 繼承 多型 1.public 任意位置訪問 2.protected 本類,子類類中訪問 3.private 本類類中訪問 2.struct class 3.this thiscall 類中普通的成員方法中有預設的引數 this this student const 普通成員方...

C 預設的六個函式

一 建構函式 1.建構函式 cmystring 1 函式名與類名相同 無返回值 物件構造時系統自動呼叫相應的建構函式 建構函式可以過載 可以在類內或者類外定義 指定作用域即可 2 初始化列表比函式內初始化更高效 對於自定義型別,在初始化時系統會自動生成初始化列表,即系統會先走一遍初始化列表,然後在呼...

C 的六個預設函式

c 有六個預設函式 分別是 1 default建構函式 2 預設拷貝建構函式 3 預設析構函式 4 賦值運算子 5 取值運算子 6 取值運算子const 這兩個類的效果相同 class person class person deafault建構函式 person const person 預設拷貝...