C++ primer 詳解派生類向基類轉換的可訪問性

派生類向基類轉換的可訪問性

c++ primer第五版 P544

1.首先談談protected作爲成員訪問符的一個情況。

  • 對類用戶不可訪問。
  • 對派生類的成員和友元可以訪問。
  • 最重要的一條性質
    派生類的成員及友元只能通過派生類對象去訪問基類的protected成員,而不能通過基類對象去訪問基類的proteced成員。
    即如下代碼:
 class Base
{
public:
    void pub_mem();
private:
    char priv_mem;
protected:
    int prot_mem;
};

class Derive :public Base
{
public:
    void f1()
    {
        prot_mem = 0;  //成員函數可以訪問基類的public和protected成員
        pub_mem();
    }

    void f2(Derive &d) //可以通過派生類對象去訪問基類的protected成員
    {
        d.prot_mem = 0;
    }

    void f3(Base &b) //不可以通過基類對象去訪問基類的protected成員
    {
        b.prot_mem = 0;
    }


private:
    int der_priv_mem = prot_mem;
};

也就是說訪問基類的protected成員就兩種方式。

  • 通過在類內,成員及友元(不是對象)直接訪問。下面會講到
  • 在類內,只能通過派生類對象訪問。

2.再談談派生列表中的訪問說明符。

  • 無影響的內容

訪問說明符對於派生類中的成員及友元是否能訪問基類中的成員,沒有任何影響。

class Base
{
public:
    void pub_mem();
private:
    char priv_mem;
protected:
    int prot_mem;
};

class Derive :private Base     //私有繼承
{
public:
    void f1()
    {
        prot_mem = 0; //成員函數可以訪問基類的public和protected成員
        pub_mem();
    }
private:
    int der_priv_mem = prot_mem;
};

可以看到,即使是private繼承,其派生類中的成員及友元依然可以訪問基類中的public,protected成員。當然不可訪問private成員。

  • 影響的內容
    影響的內容是
    (1).(類外的)派生類的對象對於基類成員的訪問權限(如果在類內成員函數內通過派生類對象訪問基類protected成員,這樣是可以的,也就是1的情況)。
    (2).還有派生類的再派生類的成員及友元對其直接基類的成員的訪問權限。
    (1)代碼如下:
class Base
{
public:
    void pub_mem();
private:
    char priv_mem;
protected:
    int prot_mem;
};

class Pub_Derive :public Base
{
public:
    void f1()
    {
        prot_mem = 0; 
        pub_mem();
    }

    void f2(Pub_Derive &d)
    {
        d.prot_mem = 0;
    }


private:
    int der_priv_mem = prot_mem;
};

class Prot_Derive :protected Base
{
public:
    void f1()
    {
        prot_mem = 0; 
        pub_mem();
    }

    void f2(Prot_Derive &d)
    {
        d.prot_mem = 0;
    }


private:
    int der_priv_mem = prot_mem;
};

class Priv_Derive :private Base
{
public:
    void f1()
    {
        prot_mem = 0; 
        pub_mem();
    }

    void f2(Priv_Derive &d)
    {
        d.prot_mem = 0;
    }


private:
    int der_priv_mem = prot_mem;
};
    Pub_Derive pubDerive;
    pubDerive.pub_mem();//正確,public繼承 訪問基類的public成員
    pubDerive.prot_mem;//錯誤,public繼承 訪問基類的protected成員
    pubDerive.priv_mem;//錯誤,public繼承 訪問基類的private成員

    Prot_Derive protDerive;
    protDerive.pub_mem();//錯誤,protected繼承 訪問基類的public成員
    protDerive.prot_mem;//錯誤,protected繼承 訪問基類的protected成員
    protDerive.priv_mem;//錯誤,protected繼承 訪問基類的private成員

    Priv_Derive privDerive;
    privDerive.pub_mem();//錯誤,private繼承 訪問基類的public成員
    privDerive.prot_mem;//錯誤,private繼承 訪問基類的protected成員
    privDerive.priv_mem;//錯誤,private繼承 訪問基類的private成員

可以看到,如果我們在這些派生類,去訪問基類的protected,public成員是沒有任何問題的,即無影響內容中所說的。
而我們在類外定義派生類對象,用這個對象去訪問基類的成員,這就和派生列表的訪問說明符有關了。

可以這樣理解,繼承是將基類的內容繼承到派生類中,而訪問說明符是將這些繼承過來的再加上訪問性質。

public:遵循基類原有的成員訪問說明符,即public protected private繼承過來仍然是public protected private。
private:將public和protected變爲private,private保持不變。
protected:將public變爲protected,private和protected保持不變。

(2)代碼如下:

class Pub_derived_from_pub :public Pub_Derive
{
    int use_base(){ return prot_mem; }//正確,因爲Pub_Derive是公有繼承Base,故基類保護成員prot_mem可訪問
};

class Prvi_derived_from_pub :public Priv_Derive
{
    int use_base(){ return prot_mem; }//錯誤,因爲Pub_Derive是私有繼承Base,故基類保護成員prot_mem不可訪問
};

class Prot_derived_from_pub :public Prot_Derive
{
    int use_base(){ return prot_mem; }//正確,因爲Pub_Derive是保護繼承Base,故基類保護成員prot_mem不可訪問
};

我們這樣理解,由於Pub_Derive公有繼承Base,那麼Base::prot_memPub_Derive中實際上是一個protected成員,那麼Pub_Derive的子類就可以在類中直接訪問其直接基類即Pub_Derive中的protected成員了。這和第1點討論的吻合。

同理,由於Priv_Derive私有繼承Base,那麼Base::prot_memPriv_Derive中實際上是一個private成員,當然無法訪問。

同理,由於Prot_Derive保護繼承Base,那麼Base::prot_memProt_Derive中實際上是一個protected成員,同Pub_Derive

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