C++的三種繼承方式詳解以及區別
目錄
C++的三種繼承方式詳解以及區別
前言
我發現有時候概念性的東西,理解起來還是很難的,於是本文用簡單的幾個例子,來說明這三種不同的繼承方式,他們之前的區別~
一、public繼承
-
基類的
public
和protected
成員的訪問屬性在派生類中保持不變
,但基類的private
成員不可直接訪問
。 -
派生類中的成員函式可以直接訪問基類中的
public
和protected
成員,但不能直接訪問基類的private
成員。 -
通過派生類的物件訪問從基類繼承的成員,只能訪問
public
成員。
#include<iostream> using namespace std; class CFather { public: int m_testA{0}; protected: int m_testB{0}; private: int m_testC{0}; }; class CSon: public CFather { void test() { m_testA = 1; // 編譯正確 :public 繼承後,在內部或者外部都可以訪問public成員 m_testB = 1; // 編譯正確 :public 繼承後,在內部可以訪問protected成員 m_testC = 1; // 編譯錯誤 :無論哪種繼承,都無法訪問private成員 } }; int main() { CSon _test; _test.m_testA = 2; // 編譯正確 :public 繼承後,在內部或者外部都可以訪問public成員 _test.m_testB = 2; // 編譯錯誤 :public 繼承後,在外部無法訪問protected成員 _test.m_testC = 2; // 編譯錯誤 :無論哪種繼承,都無法訪問private成員 system("pause"); return 0; }
二、protected繼承
- 基類的
public
和protected
成員都以private身份出現在派生類中,但基類的
private成員
不可直接``訪問。 - 派生類中的成員函式可以直接訪問基類中的
public
和protected
成員,但不能直接訪問基類的private
成員。 - 通過派生類的物件
不能直接訪問
從基類繼承的任何
成員。
#include<iostream> using namespace std; class CFather { public: int m_testA{0}; protected: int m_testB{0}; private: int m_testC{0}; }; class CSon: protected CFather { void test() { m_testA = 1; // 編譯正確 :protected 繼承後,在內部可以訪問public成員 m_testB = 1; // 編譯正確 :protected 繼承後,在內部可以訪問protected成員 m_testC = 1; // 編譯錯誤 :無論哪種繼承,都無法訪問private成員 } }; int main() { CSon _test; _test.m_testA = 2; // 編譯錯誤 :protected 繼承後,在外部無法訪問public成員 _test.m_testB = 2; // 編譯錯誤 :protected 繼承後,在外部無法訪問protected成員 _test.m_testC = 2; // 編譯錯誤 :無論哪種繼承,都無法訪問private成員 system("pause"); return 0; }
此時,可以這麼理解為 派生類 通過 protected
繼承 基類 之後 ,基類 中的 public
變成了protected
,其他保持原樣。
class CFather
{
protected:// proteced 繼承之後public變成了 proteced
int m_testA{0};
protected:
int m_testB{0};
private:
int m_testC{0};
};
三、private繼承
- 基類的
public
和protected
成員都以private
身份出現在派生類中,但基類的private
成員不可直接訪問
。 - 派生類中的成員函式可以
直接訪問
基類中的public
和protected
成員,但不能直接訪問
基類的private
成員。 - 通過派生類的物件
不能直接訪問
從基類繼承的任何
成員。
#include<iostream>
using namespace std;
class CFather
{
public:
int m_testA{0};
protected:
int m_testB{0};
private:
int m_testC{0};
};
class CSon: private CFather
{
void test()
{
m_testA = 1; // 編譯正確 :private 繼承後,在內部可以訪問public成員
m_testB = 1; // 編譯正確 :private 繼承後,在內部可以訪問protected成員
m_testC = 1; // 編譯錯誤 :無論哪種繼承,都無法訪問private成員
}
};
int main()
{
CSon _test;
_test.m_testA = 2; // 編譯錯誤 :private 繼承後,在外部無法訪問public成員
_test.m_testB = 2; // 編譯錯誤 :private 繼承後,在外部無法訪問protected成員
_test.m_testC = 2; // 編譯錯誤 :無論哪種繼承,都無法訪問private成員
system("pause");
return 0;
}
此時,可以這麼理解為 派生類 通過 private
繼承 基類 之後 ,基類 中的 public
與protected
變成了private
,其他保持原樣。
class CFather
{
private:// private 繼承之後public變成了 private
int m_testA{0};
private:// private 繼承之後protected變成了 private
int m_testB{0};
private:
int m_testC{0};
};
四、三者區別
-
public繼承方式
- 基類中所有
public
成員在派生類中為public
屬性; - 基類中所有
protected
成員在派生類中為protected
屬性; - 基類中所有
private
成員在派生類中不能使用。
- 基類中所有
-
protected繼承方式
- 基類中的所有
public
成員在派生類中為protected
屬性; - 基類中的所有
protected
成員在派生類中為protected
屬性; - 基類中的所有
private
成員在派生類中不能使用。
- 基類中的所有
-
private繼承方式
- 基類中的所有
public
成員在派生類中均為private
屬性; - 基類中的所有
protected
成員在派生類中均為private
屬性; - 基類中的所有
private
成員在派生類中不能使用。
- 基類中的所有
下表彙總了不同繼承方式對不同屬性的成員的影響結果
繼承方式/基類成員 | public成員 | protected成員 | private成員 |
---|---|---|---|
public繼承 | public | protected | 不可見 |
protected繼承 | protected | protected | 不可見 |
private繼承 | private | private | 不可見 |
五、總結
1.不管繼承方式如何,基類中的 private 成員在派生類中始終不能使用(不能在派生類的成員函式中訪問或呼叫)。
2.如果希望基類的成員能夠被派生類繼承並且毫無障礙地使用,那麼這些成員只能宣告為 public 或 protected;只有那些不希望在派生類中使用的成員才宣告為 private。
3.如果希望基類的成員既不向外暴露(不能通過物件訪問),還能在派生類中使用,那麼只能宣告為 protected。
4.基類成員在派生類中的訪問許可權不得高於繼承方式中指定的許可權。例如,當繼承方式為 protected 時,那麼基類成員在派生類中的訪問許可權最高也為 protected,高於 protected 的會降級為 protected,但低於 protected 不會升級。再如,當繼承方式為 public 時,那麼基類成員在派生類中的訪問許可權將保持不變。
後話
我們這裡說的是基類的 private 成員不能在派生類中使用,並沒有說基類的 private 成員不能被繼承。實際上,基類的 private 成員是能夠被繼承的,並且(成員變數)會佔用派生類物件的記憶體,它只是在派生類中不可見,導致無法使用罷了。private 成員的這種特性,能夠很好的對派生類隱藏基類的實現,以體現面向物件的封裝性。由於 private 和 protected 繼承方式會改變基類成員在派生類中的訪問許可權,導致繼承關係複雜,所以實際開發中我們一般使用 public。