繼承是物件導向復用的重要手段,通過繼承定義乙個類,繼承是型別之間的關係模型。共享公有的東西,實現各自本質的不同的東西。
一、三種繼承關係
public:公有繼承
protected:保護繼承
private:私有繼承
繼承是一種復用的手段,在繼承關係裡基類(父類)的成員都會成為派生類(子類)的成員,由此達到復用的目的
總結:父類中私有的成員,在子類中不可見
如果一些父類成員不想被子類物件直接訪問,但需要在子類中能訪問,就定義為保護成員,可以看出保護成員限定符是因為繼承才出現的
public繼承是乙個介面繼承,保持is-a原則(是乙個),每個父類可用的成員對子類也可用,因為每乙個子類物件也是乙個父類物件
protected/private 繼承是乙個實現繼承,保持has-a的原則(有乙個),父類的部分成員並未完全成為子類介面的一部分,所以非特殊情況不會使用這倆種繼承,在絕大多數場景下使用的都是公有繼承。
不管是哪種繼承方式,在子類內部都可以訪問父類的公有和保護成員,但是父類的私有成員子類中不可見
使用關鍵字class時,預設的繼承方式時private,使用struct時預設的繼承方式時public,不過最好寫出繼承方式
在實際應用時,一般都使用public繼承,極少情況下才使用protected/private繼承
二、繼承與轉換——賦值相容規則
子類物件可以賦值給父類物件(切片)
父類物件不能賦值給子類物件
父類的指標/引用可以指向子類物件
子類的引用/指標不能指向父類物件(可以通過強制型別轉換)
下證:子類物件能不能賦值給父類物件(可以)
父類物件能不能賦值給子類物件(不能)
子類物件能不能賦給子類的指標/引用? (可以)
子類的指標/引用能不能指向父類的物件?
子類繼承了父類,又定義了只屬於它自己的內容,所以子類的指標指向的空間肯定比父類的的大,如果將子類的指標指向父類,對齊進行操作時就會導致嚴重的後果(記憶體越界),所以不允許子類的指標/引用指向父類。但是我們可以強制型別轉化,但是這也存在著一定的風險,可能導致程式奔潰(因為強制型別轉換後,後面的內容本來不屬於父類,如果對其操作可能是越界處理,訪問記憶體越界,導致程式奔潰)
三、繼承體系中的作用域
注意:這裡的隱藏,他是只要名字一樣就會被隱藏。不管返回值,引數一樣或不一樣,並不影響。只要名字一樣,就會隱藏。
乙個簡單的隱藏例子:
子類中的f1()隱藏了父類中的f1(),所以呼叫時要按子類中的規則,加上引數
要呼叫父類中的:s.persin::f1();
隱藏(重定義)的一些坑:
class person
void f1() };
class student:public person
void f2()
void f3()
void f4()
private:
int _stunum;
};
場景一:
void test()
通過編譯,正常輸出;
場景二:
void test()
編譯通過,程式奔潰;
p->f2(),將p的位址作為第乙個形參this指標,傳遞給函式,但是在訪問_stunum時要對其進行解引用。this指標為空,對空指標解引用,程式奔潰。
但是在訪問f1()時,我們雖然將p的位址作為實參傳遞給this指標,但是並沒有對其進行解引用操作, 所以程式沒有奔潰。
場景三:
void test()
編譯通過,程式奔潰;
void test()
編譯通過,程式正常執行
雖然呼叫了成員函式,但是並沒有進行解引用,所以程式不會奔潰
c 過載,重寫 覆蓋,重定義 隱藏
關於c 的過載,重寫 又稱覆蓋 重定義 又稱隱藏 來做乙個小小的總結。過載最主要是指在同一作用域下的函式名相同,引數不同的函式過載,其強調同一作用域。同名同參,不同返回值不能作為過載,編譯器會提示函式重複定義。重寫和重定義主要在體現在繼承行為中,子類對父類函式的操作。重寫是虛函式的正確用法,指子類對...
C 過載 重寫 覆蓋 重定義 隱藏
我們經常會被過載 重寫 重定義經常被我搞混,今天就專門總結區別一下。1.過載概念 過載指的都是函式過載,函式過載就是函式的一種特殊情況,c 允許在同一作用域中宣告幾個功能類似的同名函式,這些同名函式的形参列 表 引數個數 型別 順序 必須不同,常用來處理實現功能類似資料型別不同的問題。2.構成過載的...
C 繼承之隱藏
什麼是隱藏 就是說在下面的這種情況下,父類的abc會在子類中進行隱藏,但是子類的確繼承了父類的abc函式 如果一定要使用父類中的abc,那麼必須進行特殊處理。執行結果 值得一提的是 如果父類與子類中的函式引數型別與個數不相同,也會發生隱藏現象,也就是說不會發生過載 必須使用這種寫法去呼叫父類隱藏的成...