在上一節中,我們看到了衍生類別的定義方法,用到了public的公有繼承,實際這裡一共有三種方式,分別是公有繼承、私有繼承、保護繼承。
不同的繼承方式,主要差異在於基底類別中不同存取權限的成員在衍生類別中的存取權限變化。下面一一介紹。
1. 公有繼承:
在公有繼承的模式下,其特點如下:
(1)基底類別中的公有成員,在衍生類別中仍然為公有成員,當然無論衍生裡的成員函數或衍生類別物件都可以存取。
(2)基底類別中的私有成員,無論在衍生類別的成員或衍生類別物件都不可以存取。
(3)基底類別中的保護成員,在衍生類別中仍然是保護類型,可以透過衍生類別的成員函數訪問,但派生類別物件不可以存取。
2. 私有繼承:
在私有繼承的情況下,公有型別、私有型別、受保護型別三種成員的存取權限如下:
(1)基底類別的公有和受保護類型,被衍生類別私有繼承吸收後,都變成衍生類別的私有類型,即在類別的成員函數裡可以訪問,不能在類別外訪問。
(2)而基底類別的私有成員,在衍生類別無論類別內或類別外都不可以存取。
我們可以看出來,如果為私有派生,則基類的私有成員在派生類別甚至再派生出的子類別中,都無法再使用,沒有什麼存在意義,故這種使用情況比較少。
3. 保護繼承:
保護類型的繼承,特點如下:
(1)基底類別的公有成員和保護類型成員在衍生類別中為保護成員。
(2)基底類別的私有成員在衍生類別中不能直接存取。
可以看的出來,衍生類別裡的成員函數可以存取基底類別的公有成員和保護成員,但在類別外透過衍生類別物件則無法存取它們。同樣,無論衍生類別裡的成員函數或透過類別物件都無法存取基底類別中的私有成員。
下面還是以時鐘和鬧鐘的程式碼為例,實驗基類中不同類型透過不同權限派生的存取問題。對於公有類型,無論在衍生類別的成員方法裡或類別外都可以調用,編譯無錯運行如下:
但對於私有成員,我們試著增加一行程式碼見41行。在衍生類別的成員函數中對吸收來自基底類別的H變數進行賦值,編譯得到報錯,請參閱紅色方框與下方提示:
可以看到錯誤訊息“H為私有類型”。
而對於受保護類型的,我們嘗試在基類中定義一個protected類型的變數w,並試圖在公有繼承的衍生類別方法中賦值使用,可以看到下圖的情況,完全可以存取。如下圖:
對於私有繼承,公開類型的成員在類別外存取情況:
大家可以自行上機實驗,驗證不同類型成員在公有繼承下的存取情況。
學習並實驗過後,我們可以總結如下:
1. 基底類別私有成員,無論什麼衍生權限,衍生類別內成員函數和類別外都是不可以存取的。
2. 私有繼承,無論基底類別原來什麼類型,在衍生類別外透過成員函數都不可以存取。
3. 派生類別從基底類別吸收的成員的存取權限為基底類別中存取權限和派生時派生權限兩者之中最低的一種。
並根據派生的權限、基類中定義的權限,在派生類別的類別內和類別外不同存取時的組合情況,列出下表:
公有繼承 | 保護繼承 | 私有繼承 | ||||
訪問位置 | 類內 | 類外 | 類內 | 類外 | 類內 | 類外 |
公有會員 | 可以 | 可以 | 可以 | 不可以 | 可以 | 不可以 |
保護會員 | 可以 | 不可以 | 可以 | 不可以 | 可以 | 不可以 |
私有成員 | 不可以 | 不可以 | 不可以 | 不可以 | 不可以 | 不可以 |