Protected or Private?

作爲父類的設計者,你可能會躊躇到底應該使用protected還是private來描述你的成員。那麼,讓我們來看看下面幾個Sample吧:

1、不相關的類訪問protected成員

void B::yourfun(A &a)
{
    class ASpe:public A
    {
        friend class B;
    };
    static_cast<ASpe &>(a).ProtectFun();
}

儘管static_cast<ASpe &>的結果是undefined,但是因爲這裏的static_cast通常都是no-op,而且編譯器一般都會對ASpe作空派生類優化,因此上面的代碼在實際應用中幾乎肯定可以成功。

對於一個惡意用戶而言,他的目的已經達到了。

2、調用純虛函數

class A {
protected:
    virtual void Fun() =0;
};

class B:public A
{
public:
    B() {Dummy();}

private:
    void Dummy() {Fun();}
};
class C:public B
{
public:
    virtual void Fun() {}
};

你覺得不可能調用傳說中的純虛函數?你想看看_purecall到底會作些什麼?試試上面的代碼吧。問題的根源在於父類將Fun聲明成了protected。
當然你不應當在ctor裏調用virtual函數,但是你在ctor調用Dummy的時候,並不一定會注意到Dummy內部會調用virtual函數,於是災難發生了
如果你僅僅希望子類在virtual函數中提供某種行爲,那麼把這些函數聲明成private吧

儘管上面的代碼都不符合標準,但是至少說明,你的用戶可以利用你提供的protected權限實現一些你並不希望賦予子類的功能。
如果你覺得連private都不放心(譬如邪惡的#define private public,當然它違反了標準17.4.3.1.1,因此結果是不可預期的),那麼你最好使用PImpl來實現你的接口
發佈了40 篇原創文章 · 獲贊 5 · 訪問量 21萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章