我們今天來學習C++的進階:
面向對象三大特性:封裝,繼承,多態。
封裝我們在前面已經學了,我們細細理解,我們的類的封裝,迭代器的封裝(vector的迭代器可以是他的原生指針,list迭代器不能是他的原生指針,我們進行封裝),適配器的封裝(stack和queue的封裝)。
我們今天就來學習他的第二大特性:繼承;
繼承:
繼承其實就是我們把公共的成員提取出來,方成一個單獨的類,然后讓下面的類去繼承;
這個就是設計層次的類的復用。
我們來看我們的繼承:
下?我們看到沒有繼承之前我們設計了兩個類Student和Teacher,Student和Teacher都有姓名/地址/ 電話/年齡等成員變量,都有identity?份認證的成員函數,設計到兩個類??就是冗余的。當然他們也有?些不同的成員變量和函數,?如?師獨有成員變量是職稱,學?的獨有成員變量是學號;學?的獨有成員函數是學習,?師的獨有成員函數是授課。
我們看我們的上面的兩個類,這兩個類分別是代表的是學生和老師,但是我們發現這兩個類的話,其中有一部分的函數和變量是一樣的,他們有相同的成員變量和成員函數。
這樣的話,設計是不是有一點冗余呢?是的。
這時候就是我們的繼承的用法了:
我們看這個類,我們把這兩個都有的類放到一起,構成一個新的類,這個新的類我們叫做父類。
我們看下面:
我們這里的繼承是公有的繼承,我們使用了public:來進行繼承;
然后我們看我們現在的Student和Teacher類,這兩個類現在里面有的數據就是他們自己也特有的數據,那他們以前的數據怎么辦呢?
我們把他們之前的數據存起來的(父類)繼承下來,繼承給他們。這時候這兩個類還是可以調用以前的函數和成員變量,他們都是還在的。
然后這些繼承父類的類,我們叫他子類。
繼承的方式:
如果我們想在父類里面和外面使用的話,我們就定義為public。
如果想在父類里面使用,外面不能使用的,但是繼承的子類可以使用,我們就定義為protect。
如果父類里面使用,外面不能使用,繼承的子類也不能使用的話,我們就定義為private。
當然如果是父類里面的private成員,無論怎樣繼承我們的子類都是不可見的,但是我們還有一種方法在子類中得到這個,我們可以在父類的public區域里面創建一個函數,
我們看這個代碼,我們在我們的父類的public區域里面創造一個函數,父類的話,我們是可以使用我們的父類的private的成員變量的。在這個函數我們對我們的private的變量進行調整。
這個public的成員函數我們的繼承的子類里面是可以調用的。
繼承類模板:
我們的類模板也是可以被繼承的:
我們之前實現我們的容器適配器Stack的時候,我們把我們的容器vector傳過去,現在的話,我們把我們的vector繼承給我們的Stack;
但是這個方式是沒有我們之前學習Stack的時候,實現的,我們使用的組合的方式實現效果好的。
基類和派生類之間的轉換:
我們看這個圖片:Person表示我們的基類,Student表示我們的派生類。
臨時對象:
我們看這個,我們之前學習的,我們看第一個圖片,我們的i賦值給d,int類型的賦值給double類型的,里面存在著隱式類型轉換,如果有隱式類型轉換的話,他就會產生臨時對象。
這時候我們看第二個圖片,如果我們加上引用的符號的話,這時候就會報錯,因為我們的臨時對象具有常性,所以我們要引用的話就要加上const。這才是對的。
我們再看我們的自定義類型的:
我們的這個string,我們說單參數的構造函數支持隱式類型轉換,這里"1111"
是const char*
類型的字符串字面量,這是一個常量字符串,編譯器會隱式調用std::string
對應的單參數構造函數,將const char*
類型的"1111"
轉換為std::string
類型,并初始化s1
?。
我們的第二行的這個代碼,我們引用了一個臨時對象,還是臨時對象具有常性。使用const防止被修改。
在 C++ 中,單參數的構造函數支持隱式類型轉換,是指當一個構造函數只有一個參數時,編譯器可以自動使用該構造函數將參數類型轉換為類類型。
在上述代碼中,MyClass
類有一個接受int
類型參數的單參數構造函數。在main
函數中,使用int
類型的10
初始化MyClass
類型的對象obj
,此時編譯器會自動調用單參數構造函數,將10
隱式轉換為MyClass
類型的對象。
這個都會產生臨時對象;
但是我們這里的沒有產生臨時對象;這里我們的是特殊處理;他叫復制兼容轉換;
我們繼續看:
我們的派生類對象可以賦值給我們的基類的對象(這個我們后面講解),但是我們的基類的對象不能賦值給我們的派生類。
繼承中的作用域:
我們說我們的基類和派生類都有他自己的作用域。
這兩個不同的作用域,我們可以有相同名字的變量。
我們看這個圖片,當我們的基類和我們的派生類里面都有我們的相同名字的成員變量的時候,我們在我們的派生類里面,我們訪問同名的成員變量的時候,我們訪問的是派生類里面的。
派?類和基類中有同名成員,派?類成員將屏蔽基類對同名成員的直接訪問,這種情況叫隱藏。(會把基類里面的成員變量屏蔽掉)(如果在派生類里面想要訪問基類里面的成員的話,我們就要指定我們的類域);
需要注意的是如果是成員函數的隱藏,只需要函數名相同就構成隱藏。(只要是函數的名字一樣,就構成隱藏,返回值和函數參數全都不看)。(在派生類里面把基類的函數隱藏了,如果派生類的對象想要使用基類里面的函數,我們就要指定作用域)