簡體   English   中英

我可以將基類的個別成員的狀態更改為私有嗎?

[英]Can I change the status of individual members of a base class to private?

我正在使用wxWidgets,如果你曾經使用它,你會知道基類中有很多公共函數。 我最近遇到了一種情況,我不希望直接從派生類調用方法SetText() 也就是說,派生類繼承了SetText()函數,但我不希望此函數可供客戶端使用。 相反,我提供了兩個調用SetText()新函數,但是在執行一些額外的操作之前沒有。

目前,客戶端(我!)可能忘記調用特殊函數並簡單地調用SetText() 因此,將不會執行一些額外的操作。 這些操作非常微妙,可能很容易被忽視。

那么,我可以將單個函數標記為私有,以便客戶端無法調用它們,或者只是讓客戶端無法直接調用它們(它們必須使用我的函數間接調用它)?

請注意, SetText() 不是虛擬的。

編輯:對於偶然發現這個問題的未來程序員,請檢查標記答案和Doug T.的答案。

實際上有兩種方法可以做到這一點。 Doug T.非常好地概述了第一個 - 使用私有/受保護的繼承和組合 - 所以我不會進入那個。

使用私有/受保護繼承的問題在於它掩蓋了所有內容 然后,您必須有選擇地公開您仍想要公開的成員。 如果你想讓大多數東西都保持公開,並且只是試圖掩蓋一件事,那么這可能會成為一個令人頭痛的問題。 這就需要第二種方法 - 使用using關鍵字。

例如,在您的情況下,您可以簡單地聲明您的類,如下所示:

class Child : public Parent
{
    //...
    private:
        using Parent::SetText; // overrides the access!
};

這只掩蓋了SetText方法!

但請記住,指向Child的指針總是可以轉換為指向Parent的指針,並且再次訪問該方法 - 但這也是繼承的問題:

class Parent
{
public:
    void SomeMethod() { }
    void AnotherMethod() { }
};

class ChildUsing : public Parent
{
private:
    using Parent::SomeMethod;
};

class ChildPrivateInheritance : private Parent
{
};

void main()
{
    Parent *p = new Parent();
    ChildUsing *a = new ChildUsing();
    ChildPrivateInheritance *b = new ChildPrivateInheritance();
    p->SomeMethod();             // Works just fine
    a->SomeMethod();             //  !! Won't compile !!
    a->AnotherMethod();          // Works just fine
    ((Parent*)a)->SomeMethod();  // Compiles without a problem
    b->SomeMethod();             //  !! Won't compile !!
    b->AnotherMethod();          //  !! Won't compile !!
    ((Parent*)b)->SomeMethod();  // Again, compiles fine

    delete p; delete a; delete b;
}

試圖訪問SomeMethod上的一個實例ChildUsing產生(在VS2005):

error C2248: 'ChildUsing::SomeMethod' : cannot access private member declared in class 'ChildUsing'

但是,試圖訪問任何SomeMethod AnotherMethod上的一個實例ChildPrivateInheritance產生:

error C2247: 'Parent::SomeMethod' not accessible because 'ChildPrivateInheritance' uses 'private' to inherit from 'Parent'
  1. 您可以通過執行私有繼承將每個公共設置為私有,並公開所需的接口。

     class YourWidget : private BaseClass { }; YourWidget widget; widget.SetText(); // this is private 

    這會阻止您通過基類工作並破壞“is-a”關系。 以下內容無法編譯:

     BaseClass* ptr = new YourWidget(); //error, no conversion available 

    它也會影響BaseClass每個公共成員,我不確定它是否適合wxWidgets如何工作。

  2. 您可以通過在派生類中創建私有版本來隱藏SetText 這僅在通過派生類指針訪問時有效,並且在處理基類指針時不提供任何安全性。 如果客戶端具有基類ptr,則仍將調用基類SetText

  3. 您可以包裝BaseClass而不是從它派生並公開您想要的界面。 根據您的代碼的工作方式,這可能也可能不存在。 如果你想要正常的界面但稍微改變一下,那么你將不得不重新實現你想要轉發到BaseClass每個函數。

  4. 您可以讓YourWidget繼承自第二個接口,該接口提供您希望向代碼公開的接口,並傳遞指向此接口的指針而不是指向BaseClass的指針。

      class IMyWidget { public: virtual void SpecialSetText() = 0; } class YourWidget : public BaseClass, public IMyWidget { public: void SpecialSetText() {/*use SetText in a special way*/} }; 

    然后在您的代碼中,您可以傳遞IMyWidget指針而不是BaseClass / YourWidget指針。 這為您的代碼的特定部分提供了一個特定的YourWidget接口,並防止(禁止向下轉換)接口的其他部分被使用。

根據您希望通過派生類訪問的內容,您可以使用私有(或受保護)繼承 ,這將不允許非友元類訪問繼承的成員/方法或通過在其中聲明新方法來隱藏基本方法派生類,重定向或(如果您需要額外的參數或其他)錯誤。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM