我可以将基类的个别成员的状态更改为私有吗?

时间:2011-08-24 21:09:01

标签: c++ inheritance wxwidgets

我正在使用wxWidgets,如果您曾经使用它,您将知道基类中有 lot 的公共函数。我最近遇到了一种情况,我不希望直接从派生类调用方法SetText()。也就是说,派生类继承了SetText()函数,但我不希望客户端可以使用此函数。相反,我提供了两个调用SetText()的新函数,但在执行一些额外操作之前没有。

目前,客户端(我!)可能忘记调用特殊功能,只需拨打SetText()即可。因此,将不会执行一些额外的操作。这些操作非常微妙,很容易被忽视。

那么,我可以将单个函数标记为私有,以便客户端无法调用它们,或者只是让客户端无法直接调用它们(它们必须使用我的函数间接调用它)?

请注意,SetText() 虚拟。

编辑:对于遇到此问题的未来程序员,请检查标记的答案和Doug T.'s答案。

3 个答案:

答案 0 :(得分:4)

实际上有两种方法。 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 :(得分:3)

  1. 您可以通过执行私有继承将每个 public设置为private,并公开您想要的接口。

    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的特定接口,并防止(禁止向下转换)接口的其他部分被使用。

答案 2 :(得分:0)

根据您希望通过派生类获得的访问权限,您可以使用private (or protected) inheritance,这将不允许非朋友类通过声明新的访问继承的成员/方法或hide the base method派生类中的方法,可以重定向或(如果需要额外的参数或其他内容)错误。