1. 程式人生 > 其它 >C++的三種繼承方式詳解以及區別

C++的三種繼承方式詳解以及區別

目錄

C++的三種繼承方式詳解以及區別


前言

我發現有時候概念性的東西,理解起來還是很難的,於是本文用簡單的幾個例子,來說明這三種不同的繼承方式,他們之前的區別~


一、public繼承

  • 基類的publicprotected成員的訪問屬性在派生類中保持不變,但基類的private成員不可直接訪問

  • 派生類中的成員函式可以直接訪問基類中的publicprotected成員,但不能直接訪問基類的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繼承

  • 基類的publicprotected成員都以private身份出現在派生類中,但基類的private成員不可直接``訪問。
  • 派生類中的成員函式可以直接訪問基類中的publicprotected成員,但不能直接訪問基類的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繼承

  • 基類的publicprotected成員都以private身份出現在派生類中,但基類的private成員不可直接訪問
  • 派生類中的成員函式可以直接訪問基類中的publicprotected成員,但不能直接訪問基類的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繼承 基類 之後 ,基類 中的 publicprotected變成了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。