C++編程知識快速複習(下)(精華高效全面版)

總第003篇

面向對象的基本任務是描述對象並對對象進行歸類總結。類類型與int類型一樣,也沒有任何內存分配。類的屬性和對外介面是類定義的重點和難點,原則是盡量讓內部操作私有化,提供簡單易用的介面函數。

1、類的相關問題

在定義類的數據成員時,不能像定義變數一樣進行初始化,若在定義時未指明訪問限定符,默認為private;

在定義類的方法時,若方法中不用修改類的數據成員,則最好在方法聲明的最後使用const關鍵字,表示用戶不能在此方法中修改類的數據成員。若類中包含指針成員,在const方法中不可以重新為指針賦值,但可以修改指針所指向的地址中的數據。

類中,除靜態成員可以直接訪問外,其它成員是通過對象來實現訪問的。在定義類時並沒有分配存儲空間,只有當實例化對象時,才分配存儲空間。也可以將類對象聲明為一個指針,並使用 new運算符為其分配內存,如下所示:

若將類對象聲明為常量指針,則只能調用類中的常量方法。

2、構造函數與析構函數

每個類都有構造函數與析構函數,構造函數在定義對象時被調用,析構函數在對象釋放時被調用。構造函數負責類對象生成之前的初始化,析構函數負責對象銷毀後的處理。

構造函數沒有返回值,若用戶沒有提供構造函數和析構函數,則系統使用默認的構造析構函數。一個類可以包含多個構造函數,各函數通過重載來進行區分,下面是指針調用參數構造函數進行初始化:

類體中定義的數據成員不能初始化,故類中初始化只能藉助構造函數的初始化列表實現。類成員函數,若在類體中定義,函數前即使沒有使用inline,該成員函數也被認為是內聯函數。

析構函數沒有返回值,也沒有參數,故不能重載。

3、複製構造函數

複製構造函數與類的其它函數構造類似,以類名作為函數的名稱,第一個參數為該類的常量引用類型。

下面的三種情況要用到複製構造函數

對象以值傳遞的方式傳入函數參數;

對象以值傳遞的方式從函數返回;

對象需要通過另外一個對象進行初始化;

編譯器有默認的拷貝構造函數,這個函數僅僅是使用老對象的數據成員的值對「新對象」數據成員一一進行賦值,這稱為淺拷貝,即只是對象中數據成員進行簡單的賦值,這種方式在對象中存在動態成員時則會出現問題,比如對象中的指針。淺拷貝只是使兩個指針有相同的值,而不是我們需要的兩塊不同的地址。

深拷貝,對於對象中動態成員,不僅僅賦值,還重新動態分配空間,從而使得指針指向兩塊不同的內存,但內存中的值相同。

在編寫函數時,盡量按引用方式傳遞參數,這樣可以避免調用複製構造函數,可以極大地提高程序效率。也可以將拷貝函數放在private中,從而防止默認拷貝的發生。

4、靜態類成員

普通類成員只能通過實例化對象訪問,靜態類成員還可以通過類名直接訪問,訪問時用::域訪問符。在定義靜態數據成員時,要在類體外部對靜態數據成員初始化。靜態數據成員是被所有類對象共享的。

靜態數據成員可以是當前的類型,而其他數據成員只能是當前類的指針或引用類型,如:

針對靜態數據成員有如下幾點:

靜態數據成員可以作為成員函數的默認參數,但是普通成員不可以;

類的靜態成員函數只能訪問類的靜態成員,不能訪問普通數據成員;

靜態成員函數末尾不能用const關鍵字修飾;

靜態數據成員和靜態成員函數在類體之外初始化或定義時,去掉static關鍵字;

5、運算符重載

運算符重載要用到operator關鍵字,它其實是函數重載的一種,因為運算符本來就是一個函數。對於重載的運算符,兩個函數不能交換順序,重載是什麼順序,只能用這各順序調用。

對於++和--運算符,由於涉及前置和後置,故默認情況下,重載運算符沒有參數,表示是前置運算;若用整型int作為參數,則表示後置運算。

並不是所有的運算符都可以重載,大多數是可以重載的,但是::,?,:,. 是不能重載的。

6、有關類的sizeof問題

空類也會被實例化,編譯器會給類隱含添加一個位元組,故空類的sizeof()結果為1;sizeof()用來計算字元串的長度時包含」」,strlen()統計的長度不包含」」。

構造函數、析構函數都不歸入sizeof()統計範圍之內。

虛函數由於要維護在虛函數表中的位置,故要佔據一個指針的大小。

靜態成員也不歸入sizeof()統計範圍。

總起來說,類的大小與非靜態成員大小和虛函數有關,與其他普通成員函數無關。類的大小也遵守內存分配時的位元組對齊規則:

7、友元類與友元方法

當用戶希望另一個類可以訪問當前類的私有成員時,可以在當前類中將另一個類作為自己的友元類。友元即朋友,私有成員只有朋友可以訪問。

若只想讓某個成員函數訪問類的私有成員,則可以將此函數聲明為類的友元函數,即在函數返回值前加上friend關鍵字。友元函數不僅可以是類成員函數,也可以是全局變數函數。

8、引用和指針的區別

引用是一個變數的別名,引用被創建的同時必須被初始化,指針可以在任何時候被初始化;

不能有NULL引用,引用必須與合法的存儲單元關聯,指針則可以是NULL;

引用一旦被初始化,就不能改變引用關係,指針則可以隨時改變所指的對象。

9、類的繼承

繼承是面向對象的主要特徵之一,它使一個類可以從現有類中派生,而不必重新定義一個新類,類繼承時使用「:」運算符。

類繼承與訪問關係如下表:

用public繼承時,原類中public和protected在派生類中類型不變;

用protected繼承時,原類中public和protected在派生類中都變成protected類型;

用private繼承時,原類中public和protected在派生類中都變為private類型;

用戶在父類派生子類時,可能存在一種情況,即在子類中定義了一個與父類同名的方法,此時稱子類隱藏父類方法,這樣父類中所有的同名方法包括重載方法均被隱藏。若要訪問父類中的方法,可用域訪問的方式。

在派生完一個子類後,可以定義一個父類指針,通過子類構造函數為其創建對象。因為編譯器對同名方法是靜態綁定的,即根據對象定義的類型來確定調用哪個類方法。

在定義方法時,在方法的前面使用virtual關鍵字,這種是虛方法,使用虛方法可以實現動態綁定,即根據對象運行的類型來確定調用哪個類的方法。在父類中定義的虛方法,在子類中同名的方法,即使前面沒有virtual關鍵字,也為虛方法。

純虛方法:

C++中除了能定義虛方法外,還可定義純虛方法,也即抽象方法。一個包含純虛方法的類稱為抽象類。抽象類不能實例化,不能當返回值,不能做函數參數,但可以設置指針,它常用於介面的實現。

抽象類常作為其它類的父類,從抽象類派生的子類要實現父類中所有的純虛方法。定義純虛函數的意義在於告訴子類,這個介面是一定要繼承的,並且要重寫函數體,增強它的功能。

10、子類對象的創建和釋放

當從父類派生一個子類,定義一個子類對象時,它將依次調用父類構造函數、子類構造函數,在釋放對象時,先調用子類析構函數,再調用父類析構函數;

當定義一個父類對象,調用子類創建一個對象時,它依次調用父類構造函數、子類構造函數,在釋放時分兩種情況:

1.析構函數不是虛函數,則只調用父類析構函數;

2.析構函數是虛函數(父類),則先調用子類的析構函數,再調用父類析構函數。

由此可見,若父類不是虛析構函數,在子類分配了空間,沒有調用了類的析構函數會產生內存泄漏,因此在編寫函數時,析構函數常用虛函數。

11、多繼承

多繼承是子類可以繼承多個父類,各父類間用逗號隔開,都要帶關鍵字。若不同父類中有同名方法,子類實例在訪問時要指明父類的名稱。多繼承的繼承鏈不能有環,可以用UML語言畫出繼承圖。

在多繼承時,通常第三代子類中存在兩個父類的備份,C++提供了一種虛繼承機制使之只有一個備份,方法是在兩個子類繼承父類時,加上virtual關鍵字。虛繼承不再從第一代父類開始創建構造函數,直接從兩個子類開始創建。

12、類模板

類模板能夠為類的數據成員、成員函數的參數、返回值提供動態參數化的機制,使用戶可以方便地設計出功能更為靈活的類。

類模板中也可以設置靜態數據成員,不同類型的模板實例都有各自的靜態數據成員,同一類型各實例共享靜態數據成員。


END,下篇繼續!!!

本文首發於微信公眾號:實戰開發者。可以掃下方二維碼或微信搜索關注,與小編一起進步。

weixin.qq.com/r/EETfx-3 (二維碼自動識別)

推薦閱讀:

TAG:C編程語言 | 互聯網 | 編程語言 |