C++基礎知識: 公有繼承,保護繼承,私有繼承的總結,私有繼承的用意何在


今天被問到C++中私有繼承的作用是什麼?第一反應是關於訪問權限的改變,基類被子類私有繼承後,基類中即使是共有public,保護protected的成員變量或者成員函數都會在子類中變爲私有成員和私有成員變量,子類的派生類或者子類的對象再也無法訪問這些成員和成員變量。


其實,這個回答只答出了最爲基本的概念,那就是私有繼承對訪問權限的改變。 但是,更爲深處的理解是,既然私有繼承這麼小衆化,爲什麼我們還要使用私有繼承?


回答之前,再來複習一下public,protected,private的作用


作用域

1.  類的一個特徵就是封裝, pubic 和 private 作用就是實現這一目的

Public:  可以被該類中的函數,子類的函數,友元函數訪問,也可以由該類的對象訪問


Protected: 可以被該類中的函數,子類的函數,友元函數訪問, 但不可以被該類的對象訪問(類外)


Private: 只能被該類中的函數,友元函數訪問, 不可以被子類的函數訪問,也不可以被該類的對象訪問


附上例子說明:

#include<iostream>
#include<assert.h>

using namespace std;

class A
{public:
  int a;
  A(){    a1 = 1;    a2 = 2;    a3 = 3;    a = 4;  }
  void fun()
  {
    cout << a << endl;    //正確
    cout << a1 << endl;   //正確
    cout << a2 << endl;   //正確,類內訪問
    cout << a3 << endl;   //正確,類內訪問
  }
public:
  int a1;
  void publicfun(){}

protected:
  int a2;
  void protectedfun(){}

private:
  int a3;
  void privatefun(){}

};

int main()
{
  A itema;
  itema.a = 10;    //正確
  itema.a1 = 20;    //正確
  itema.publicfun(); // 正確
  itema.a2 = 30;    //錯誤,類外不能訪問protected成員
  itema.protectedfun(); //錯誤,類外不能訪問protected成員函數
  itema.a3 = 40;    //錯誤,類外不能訪問private成員
  itema.privatefun(); //錯誤,類外不能訪問private成員函數
  system("pause");
  return 0;
}

繼承中的特點:


1. public 繼承: 父類public,protected, private成員或者成員函數的訪問屬性在子類中變爲public,protected, private, 這是一個典型的 “接口” 繼承

2. protecte的繼承: 父類public,protected, private成員或者成員函數的訪問屬性在子類中變爲protected,protected, private, 這是一個“實現”繼承

3. private繼承:  父類public,protected, private成員或者成員函數的訪問屬性在子類中變爲private,private, private, 這也是一種“實現”繼承


但無論那種繼承方式,上面兩點沒有變化:

1 private 成員只能被本類(友元)訪問,不能被派生類訪問,也不能被類對象訪問

2 protected成員可以被派生類訪問, 不能被類對象訪問


現在講講 私有繼承的意義: 


私有繼承的含義:私有繼承意味着 "用...來實現"
如果使類D私有繼承於類B,這樣做是因爲你想利用類B中已經存在的某些代碼,而不是因爲類型B的對象和類型D的對象之間有什麼概念上的關係
因而,私有繼承純粹是一種實現技術。

私有繼承意味着只是繼承實現,接口會被忽略。如果D私有繼承於B,就是說D對象在實現中用到了B對象,僅此而已
私有繼承在軟件 "設計" 過程中毫無意義,只是在軟件 "實現" 時纔有用。


以下節選自http://blog.chinaunix.net/uid-20235103-id-1970688.html

看完之後花時間理解了一下,發現確實豁然慨然,私有繼承絕不僅僅是在訪問權限上的考慮,再往深層次考慮,就會發現,和 組合 設計模式相比較,私有繼承也是一種 has a 的實現,兩個類之間不再是 is a的關係,所以私有繼承情況下,編譯器不會爲了使 函數調用成功而需要將子類隱式轉換爲父類。 


附上案例

	class B {};
	class D: public class B{};
	class E: private classB{};
	void eat(B& b);

	int maint(int arg, char** argc)
	{
		B b;
		D d;
		E e;
		eat (b) ;  // correct, 
		eat(d); // also correct, since D "is a " of B, public inhertance is an interface inheratance, compiler will static-cast it for success of compilation
		eat(e);  // NOT correct, e private inherits B, e is not "is a" of B, only indicate e "has a" of B, compiler won't static cast it for compilation success
	}


  private inheritance(私有繼承)更可能在以下情況中成爲一種設計策略,當你要處理的兩個 classes(類)不具有 is-a(是一個)的關係,而且其中的一個還需要訪問另一個的 protected members(保護成員)或需要重定義一個或更多個它的 virtual functions(虛擬函數)。甚至在這種情況下,我們也看到 public inheritance 和 containment 的混合使用通常也能產生你想要的行爲,雖然有更大的設計複雜度。謹慎使用 private inheritance(私有繼承)意味着在使用它的時候,已經考慮過所有的可選方案,只有它纔是你的軟件中明確表示兩個 classes(類)之間關係的最佳方法。

  Things to Remember


 
 ·private inheritance(私有繼承)意味着 is-implemented-in-terms of(是根據……實現的)。它通常比 composition(複合)更低級,但當一個 derived class(派生類)需要訪問 protected base class members(保護基類成員)或需要重定義 inherited virtual functions(繼承來的虛擬函數)時它就是合理的。

  ·與 composition(複合)不同,private inheritance(私有繼承)能使 empty base optimization(空基優化)有效。這對於致力於最小化 object sizes(對象大小)的庫開發者來說可能是很重要的。






發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章