天天看點

通路控制 protected, public, private 對比

OOP 3大特性: 資料抽象,繼承,動态綁定 3中通路标号 protected, public, private 對比

用 類進行資料抽象;用繼承類繼承基類的成員,實作繼承;通過将基類相應函數聲明為virtual,是編譯器在運作時決定調用基類函數or派生類函數 完成 動态綁定,即表現 多态性。 多态性:利用繼承和動态綁定,通過基類指針和引用來表現。 動态綁定兩個條件:1. 虛函數,2. 指針或引用

class Item_book

{

     private :

        std : :string isdn;

     protected :

         double price;

     public :

        std : :string book()  const {  return isdn; } 

};

class Bulk_item : : public Item_book

{

    ...

};

void Bulk_item : :memfcn( const Bulk_item  &d,  const Item_base  &b)

{

    cout <<isdn; // error: no access to isdn which is private member in Item_base   (1)

     double ret  = price;  //ok: use this->price                                     (2)

    ret  = d.price; // ok: use price from a Bulk_item object                       (3)

    ret  = b.price;  // error: no access to price from an Item_base                 (4)

}

# include  <iostream >

using  namespace std;

class Base

{   

private :

     int age;

protected :

     int num;

public :     Base()     {          num = 5;      }      void set_num( const Base& a)

    {

        cout <<a.num <<endl;

    }

     virtual  void show()

    {

        num  =  1;

        cout <<num <<endl;

    }

};

class Devi  :  public Base

{

public :

     void show()

    {

        num  =  2;

        cout <<num <<endl;

    }

     void test( const Base  &a,  const Devi &b)

    {

        cout <<b.num <<endl;   //(5)

    }

};

int main()

{

    Base b, a;

    Devi d;     b.set_num(a);         (7)

    b.show();

    d.show();   //ok   protected  num可被子類使用

    d.test(b, d); 

     //cout<<d.num; //error  protected  num 不可被子類  對象使用  (6)

     return  0;

} 區分(5)(6)的差別,一個在 類的成員函數定義中(可以通過 類對象調用其保護成員,如公有成員一樣),一個在 類定義外部

總結: 通路控制與繼承: public: private: 隻能被基類的成員和友元函數通路。不能被類的對象通路。同時不能被派生類(的成員函數)通路。如下 (1)。 protected:可以被派生類(的成員 (2))通路。不可以被派生類對象通路 (6) 。 例外: ( 例外 :在 派生類内部  可以通過派生類對象通路其基類的protected)如下(3),同時 對比下圖(5)和(6); 但不能被基類的對象通路(對于基類,相當于基類的private)如下(4);基類在基類内部可以通過基類對象通路其protected成員(7) 即 派生類可以通路基類 protected 和 public 中的成員。

公有、私有、保護繼承 對類所繼承的成員的通路由    基類的成員通路級别和派生類 派生清單中使用的 通路标号 共同控制。 派生類可以 進一步限制,但不能放松對繼承的成員通路。

派生類中的通路級别(3種繼承方式): public:基類成員保持自己的通路級别:基類的public->派生類的public,基類的protected -> 派生類的protected。  protected:基類的public和protected成員在派生類中為proteced成員 private:基類的所有成員在派生類中為private成員。

class Base

{

public :

     void basemen();

protected :

     int i;

private :

    std : :string isdn;

    ....

};

class Public_derived :  public Base

{

     int use_base() {  return i; }  //ok: as proteced member in Public_derived

     //...

};

class Private_derived :  private Base  //注意,對比下面

{

     int use_base()  { return i;}  // ok: i is protected member in Base, private member in Pivate_derived

     int print_isdn() {cout <<isdn; }  //error: isdn is private member in Base 

};

派生通路标号 還控制來自非直接派生類的通路:

class Derived_from_Private :  public Private_derived

{

     //error: Base::i  is private in Private_derived

     int use_base() { return i;}

};

class Derived_from_Private :  public Public_derived

{

      //ok: Base::i  remain proteced in Public_derived

     int use_base() { return i;}

}

struct VS  class struct 定義的類 預設範圍級别為public類型,定義的派生類 預設具有public繼承 class 定義的類 預設範圍級别為 private類型,定義的派生類 預設具有 private繼承

轉換與繼承 可以将 派生類轉換為基類---通過初始化或複制。 一般調用基類的複制構造函數或指派函數。 例:

Item_base item;                  //object of base type

Bulk_item bulk;                  //object of derived type

//ok:use Item_base::Item_base(const Item_base&) constructor

Item_base item(bulk);            // bulk is "slice down" to its Item_base portion

//ok:use Item_base::operator = (const Item_base&) 

item  = bulk;                     // bulk is "slice down" to its Item_base portion

基類   不能 自動  轉換為 派生類,否則派生類會通路 不存在的成員 (基類不存在的成員), 除非在 知道 基類向派生類轉換為 安全時,可以使用 static_cast強制編譯器進行轉換。或是 用 dynamic_cast 申請在運作時進行檢測。

參照 《C++ primer》 第15章