派生類成員的訪問屬性:
C++繼承方式總共分為以下幾種:public、private、protected三種(它們直接影響到派生類的成員、及其對象對基類成員訪問的規則)。
(1)public(公有繼承):繼承時保持基類中各成員屬性不變,並且基類中private成員被隱藏。派生類的成員只能訪問基類中的public/protected成員,而不能訪問private成員;派生類的對象只能訪問基類中的public成員。
(2)private(私有繼承):繼承時基類中各成員屬性均變為private,並且基類中private成員被隱藏。派生類的成員也只能訪問基類中的public/protected成員,而不能訪問private成員;派生類的對象不能訪問基類中的任何的成員。
(3)protected(保護性繼承):繼承時基類中各成員屬性均變為protected,並且基類中private成員被隱藏。派生類的成員只能訪問基類中的public/protected成員,而不能訪問private成員;派生類的對象不能訪問基類中的任何的成員。
由上表可知:
public繼承:不改變基類成員的訪問控制。
private繼承:派生類所繼承的基類成員的訪問控制都變為private。
protected繼承:基類中的private成員的訪問控制不變,其余的都變為protected。
基類的 public成員被派生類繼承,且在派生類中是可見的(visible in the derived class)。
基類的 private成員被派生類繼承,但在派生類中是不可見的(not visible in the derived class)。
受保護成員 protected Members
以下面兩個例子來說明受保護成員的可見性。
class BC { public: void set_x( int a ) { x = a; } protected: int get_x( ) const { return x; } private: int x; }; class DC : public BC { public: void add2() { int c=get_x();//可以執行 set_x(c+2);//可以執行 } } void g() { DC d; d.get_x( );//在客戶代碼中不可見,不能夠執行 }
class BC { protected: int get_w( ) const; //…… }; class DC : public BC { public: int get_val( ) const { return get_w( );//派生類中可見,可以執行 } void base_w( const BC& b ) const { cout << b.get_w( ) << endl;//客戶代碼中不可見,不能夠執行 } };
保護成員是專為繼承機制而設的。
受保護成員(A protected member)僅在自己的類和其派生類中是可見的。
繼承方式不會影響基類成員在派生類中的能見度。
名字隱藏 Name hiding
如果在派生類中添加了成員(數據、函數),其與基類的成員重名,本地成員(the local member)隱藏繼承來的成員 ( hides the inherited member)。
以下面的代碼為例:
class BC { public: void h( float ); }; class DC : public BC { public: void h( char[ ] ); };
DC繼承自BC,其中BC含有void h(float)函數,DC中含有void h(char[])函數,這兩個函數的簽名不同,那么是否能夠構成函數的重載呢?
對於下面的兩行代碼都能夠執行?
void f ( ) { DC d1; d1.h( "Boffo!" );//可以執行 d1.h( 707.7 );//不可以執行 }
其實這種想法是不對的,重載必須是同一級的函數才能構成,而這兩個函數的級別是不一致的,本地成員void h(char[])將會隱藏繼承來的成員 void h(float)!!
void f ( ) { DC d1; d1.BC::h( 707.7 );//這樣寫是可以的 }
再就一個例子
對於一個實現數組升序的類繼承自一個數組類。
class Array { public: void insert(int X) { 將X插入到 last_pos 指定的位置; last_pos++; } private: int last_pos; //…… }; class AscArray : public Array { public: void insert( int X ) { 確定插入的位置,並將X插入 // ... } // ... };
其調用函數如下調用語法是正確的,但是其內涵錯誤
void f (AscArray& as ) { as.insert( 10 );//正確,排序數組類中插入10然后實現排序 as.Array::insert(10);//不正確,使用了數組類的插入方法,將10插入到了數組尾部,並不能實現排序功能 }
調整可訪問性 Adjusting access
一個繼承成員的訪問控制可能通過使用using聲明( using declaration)改變。
還是上面那個例子。
class AscArray : public Array { private: using Array::insert; //將基類的public成員的外部訪問權降低,使得無法通過派生類對象訪問該成員! public: void insert( int X ) { 確定插入的位置,並將X插入 // ... } // ... }; void f(AscArray& as ) { as.insert( 10 );//正確 as.Array::insert(10);//運行錯誤 }
在使用using聲明時,基類中公有的成員在公共派生類中必須是公有的,只有這樣才能保證公有繼承時“派生類對象是一個基類對象”的邏輯關系。
在基類中的private成員,不能在派生類中任何地方用using聲明。
同時,在基類中的protected成員,可在public派生下通過using聲明改為public成員。
#include <iostream> using namespace std; class A { protected: void PrintA( ) { cout << "A::Print"<<endl ; } }; class B: public A { public: using A::PrintA;//改為公有 public: void PrintB( ) { cout << "B::Print" <<endl; } }; int main( ) { A a; B b; b.PrintB( ); b.PrintA( ); return 0; }