天天看點

詳談C++保護成員和保護繼承

protected 與 public 和 private 一樣是用來聲明成員的通路權限的。由protected聲明的成員稱為“受保護的成員”,或簡稱“保護成員”。從類的使用者角度來看,保護成員等價于私有成員。但有一點與私有成員不同,保護成員可以被派生類的成員函數引用。

如果基類聲明了私有成員,那麼任何派生類都是不能通路它們的,若希望在派生類中能通路它們,應當把它們聲明為保護成員。如果在一個類中聲明了保護成員,就意味着該類可能要用作基類,在它的派生類中會通路這些成員。

在定義一個派生類時将基類的繼承方式指定為protected的,稱為保護繼承,用保護繼承方式建立的派生類稱為保護派生類(protected derived class ), 其基類稱為受保護的基類(protected base class ),簡稱保護基類。

保護繼承的特點是:保護基類的公用成員和保護成員在派生類中都成了保護成員,其私有成員仍為基類私有。也就是把基類原有的公用成員也保護起來,不讓類外任意通路。

表11.3 基類成員在派生類中的的通路屬性

基類中的成員 在公用派生類中的通路屬性 在私有派生類中的通路屬性 在保護派生類中的通路屬性
私有成員 不可通路 不可通路 不可通路
公用成員 公用 私有 保護
保護成員 保護 私有 保護

保護基類的所有成員在派生類中都被保護起來,類外不能通路,其公用成員和保護成 員可以被其派生類的成員函數通路。

保護基類的所有成員在派生類中都被保護起來,類外不能通路,其公用成員和保護成員可以被其派生類的成員函數通路。

比較一下私有繼承和保護繼承(也就是比較在私有派生類中和在保護派生類中的通路屬性), 可以發現,在直接派生類中,以上兩種繼承方式的作用實際上是相同的:在類外不能通路任何成員,而在派生類中可以通過成員函數通路基類中的公用成員和保護成員。但是如果繼續派生,在新的派生類中,兩種繼承方式的作用就不同了。

例如,如果以公用繼承方式派生出一個新派生類,原來私有基類中的成員在新派生類中都成為不可通路的成員,無論在派生類内或外都不能通路,而原來保護基類中的公用成員和保護成員在新派生類中為保護成員,可以被新派生類的成員函數通路。

大家需要記住:基類的私有成員被派生類繼承(不管是私有繼承、公有繼承還是保護繼承)後變為不可通路的成員,派生類中的一切成員均無法通路它們。如果需要在派生類中引用基類的某些成員,應當将基類的這些成員聲明為protected,而不要聲明為private。

如果善于利用保護成員,可以在類的層次結構中找到資料共享與成員隐蔽之間的結合點。既可實作某些成員的隐蔽,又可友善地繼承,能實作代碼重用與擴充。

通過以上的介紹,可以知道以下幾點。

1) 在派生類中,成員有4種不同的通路屬性:

  • 公用的,派生類内和派生類外都可以通路。
  • 受保護的,派生類内可以通路,派生類外不能通路,其下一層的派生類可以通路。
  • 私有的,派生類内可以通路,派生類外不能通路。
  • 不可通路的,派生類内和派生類外都不能通路。

表11.4 派生類中的成員的通路屬性

派生類中的成員 在派生類中 在派生類外部 在下層公用派生類中
派生類中通路屬性為公用的成員 可以 可以 可以
派生類中通路屬性為受保護的成員 可以 不可以 可以
派生類中通路屬性為私有的成員 可以 不可以 不可以
在派生類中不可通路的成員 不可以 不可以 不可以

需要說明的是:

  • 這裡所列出的成員的通路屬性是指在派生類中所獲得的通路屬性。
  • 所謂在派生類外部,是指在建立派生類對象的子產品中,在派生類範圍之外。
  • 如果本派生類繼續派生,則在不同的繼承方式下,成員所獲得的通路屬性是不同的,在本表中隻列出在下一層公用派生類中的情況,如果是私有繼承或保護繼承,大家可以從表11.3中找到答案。

2) 類的成員在不同作用域中有不同的通路屬性,對這一點要十厘清楚。一個成員的通路屬性是有前提的,要看它在哪一個作用域中。有的讀者問:“一個基類的公用成 員,在派生類中變成保護的,究竟它本身是公用的還是保護的?”應當說:這是同一個成員在不同的作用域中所表現出的不同特征。例如,學校人事部門掌握了全校師生員工的資 料,學校的上司可以查閱任何人的材料,學校下屬的系隻能從全校的資料中得到本系師生員工的資料,而不能查閱其他部門任何人的材料。如果你要問:能否查閱張某某的材料, 無法一概而論,必須查明你的身份,才能決定該人的材料能否被你“通路”。

在未介紹派生類之前,類的成員隻屬于其所屬的類,不涉及其他類,不會引起歧義。 在介紹派生類後,就存在一個問題:在哪個範圍内讨論成員的特征,同一個成員在不同 的繼承層次中有不同的特征。為了說明這個概念,可以打個比方,汽車駕駛證是按地區核發的,北京的駕駛證在北京市範圍内暢通無阻,如果到了外地,可能會受到某些限制,到了外國就無效了。同一個駕駛員在不同地區的權利是不同的。又譬如,到醫院探視病人,如 果允許你進人病房近距離地看望病人并與之交談,則可對病人了解比較深人;如果隻允許你在玻璃門窗外探視,在一定距離外看到病人,隻能對病人狀況有粗略的印象;如果隻允許在病區的走廊裡通過電視看病人活動的片段鏡頭,那就更間接了。人們在不同的場合下對同一個病人,得到不同的資訊,或者說,這個病人在不同的場合下的“可見性”不同。

平常,人們常習慣說某類的公用成員如何如何,這在一般不緻引起誤解的情況下是可以的。但是決不要誤認為該成員的通路屬性隻能是公用的而不能改變。在讨論成員的通路屬性時,一定要說明是對什麼範圍而言的,如基類的成員a,在基類中的通路屬性是公用的,在私有派生類中的通路屬性是私有的。

下面通過一個例子說明怎樣通路保護成員。

[例11.3] 在派生類中引用保護成員。

  1. #include <iostream>
  2. #include <string>
  3. using namespace std;
  4. class Student//聲明基類
  5. {
  6. public:
  7. //基類公用成員
  8. void display( );
  9. protected:
  10. //基類保護成員
  11. int num;
  12. string name;
  13. char sex;
  14. };
  15. //定義基類成員函數
  16. void Student::display( )
  17. {
  18. cout<<"num: "<<num<<endl;
  19. cout<<"name: "<<name<<endl;
  20. cout<<"sex: "<<sex<<endl;
  21. }
  22. class Student1: protected
  23. Student //用protected方式聲明派生類Student1
  24. {
  25. public:
  26. void display1( );//派生類公用成員函數
  27. private:
  28. int age;//派生類私有資料成員
  29. string addr;//派生類私有資料成員
  30. };
  31. void Student1::display1( )//定義派生類公用成員函數
  32. {
  33. cout<<"num: "<<num<<endl;//引用基類的保護成員,合法
  34. cout<<"name: "<<name<<endl;//引用基類的保護成員,合法
  35. cout<<"sex: "<<sex<<endl;//引用基類的保護成員,合法
  36. cout<<"age: "<<age<<endl;//引用派生類的私有成員,合法
  37. cout<<"address: "<<addr<<endl; //引用派生類的私有成員,合法
  38. }
  39. int main( )
  40. {
  41. Student1 stud1; //stud1是派生類Student1類的對象
  42. stud1.display1( ); //合法,display1是派生類中的公用成員函數
  43. stud1.num=10023; //錯誤,外界不能通路保護成員
  44. return 0;
  45. }

在派生類的成員函數中引用基類的保護成員是合法的。基類的保護成員對派生類的外界來說是不可通路的(例如,num是基類Student中的保護成員,由于派生類是保護繼承,是以它在派生類中仍然是受保護的,外界不能用stud1.num來引用它),但在派生類内,它相當于私有成員,可以通過派生類的成員函數通路。可以看到,保護成員和私有成員不同之處,在于把保護成員的通路範圍擴充到派生類中。

注意:在程式中通過派生類Student1的對象stud1的公用成員函數display1去通路基類的保護成員num、name和sex,不要誤認為可以通過派生類對象名去通路基類的保護 成員(如stud1.num是錯誤的)。

轉載于:https://www.cnblogs.com/skl374199080/p/4142847.html