C++基礎(三)
一、C++的三大特性
封裝、繼承、多型
多型意味著多種形態,當類之間存在層次結構,且不同類之間通過繼承關聯時,就會用到多型。
需要在基類中將公有函式名設定為虛擬函式,此時編譯器就會通過指標內容呼叫函式,而非通過指標型別呼叫函式(靜態多型)。
1、多型
普通函式的繼承是實現繼承,派生類繼承了基類函式,繼承的是函式的實現,虛擬函式的繼承是一種介面繼承,派生類繼承的是基類虛擬函式的介面,目的是為了重寫,達成多型。所以,如果不是為了實現多型,不要把函式定義成虛擬函式
2、虛表與vptr指標
當類中宣告虛擬函式的時候,編譯器會在類中生成一個函式虛表。虛擬函式表是一個儲存類成員函式指標的資料結構,這個虛擬函式表由編譯器自動生成和維護,virtual成員函式會被編譯器放入虛擬函式表中,存在虛擬函式時,每個物件中都有一個指向虛擬函式表的指標。
二、const的作用
1、定義const常量,可以防止意外的修改
2、相較於#define便於進行型別安全檢查
3、相較於#define更節約記憶體空間
4、編譯器不為普通const菜場裡那個分配儲存空間,使得沒有儲存和讀記憶體的操作,提高了效率。
三、解構函式
是類的一種特殊的成員函式,會在每次刪除所建立的物件時執行,它不會返回任何值,也不會有任何引數。
解構函式有助於在跳出程式前釋放資源。
基類的解構函式最好寫成虛基類,此時派生類的解構函式會自動重寫基類的解構函式,可以理解為編譯器對解構函式做了特殊處理。
四、行內函數(inline)
目的是提高函式的執行效率,但是必需要和函式定義體放在一起,僅與函式宣告體放在一起沒有任何意義。
缺點:濫用行內函數會讓程式變慢。
五、鑽石繼承問題(菱形繼承)
問題描述:D類中會有兩份A類的成員(包括資料和方法),所以D的物件會包含A的兩個子物件,這會導致呼叫函式不明確(D的物件不清楚應該呼叫B中的函式還是C中的函式)。
解決方法:class B : virtual public A{};
class C : virtual public A{};
即為B、C虛繼承A類後,類D中將會只有一個A的子物件。
六、同名覆蓋問題
場景描述:父類指標指向子類時,呼叫了一個在父類和子類中均存在的函式(在子類中把父類的此函式進行了重寫),此時呼叫的是哪個函式。
1、父子間的賦值相容
(1)子物件可以直接賦值/初始化父類物件。
(2)父類指標可以直接指向子類物件。
(3)父類引用可以直接引用子類物件。
2、父類指標(引用):當使用父類指標直接指向(引用)子物件時
(1)子類退化為父類物件。
(2)只能訪問父類中定義的成員
(3)可以直接訪問被子類覆蓋的同名成員。
3、特殊的同名函式
子類中可以重定義父類中已經存在的同名函式,這種重定義發生在繼承中,稱為函式重寫。
若採用父類指標指向子類物件,並呼叫在子類中重寫過的函式,此時會呼叫父類物件中的函式為了解決此問題,引入多型的概念(通過虛繼承避免)。
七、引用
引用就是某一變數(目標)的一個別名,對引用的操作和對變數直接操作完全一樣。
引用的宣告方法:型別識別符號 &引用名=目標變數名。
int a;
int &ra =a;此時定義了一個引用ra,它是變數a的引用,也即別名。
引用只是一個別名,本身不是資料型別,也不佔用儲存單元,系統也不分配儲存單元,對引用取地址等價於對目標變數取地址。
無法建立對陣列的引用。
1、常引用
const型別識別符號 &引用名=目標變數名
避免通過引用更改目標變數的值,達到了引用的安全性。
2、引用作為返回值
(1)、以引用返回函式值的時候,定義函式時需要在函式名前加&。
(2)、用引用返回一個函式值的好處是,在記憶體中不產生被返回值的副本,可以節約記憶體開銷。