如何从基类公开继承,但在派生类中从基类私有一些公共方法?

时间:2010-06-07 03:16:17

标签: c++

例如,课程Base有两种公开方法:foo()bar()。类Derived继承自类Base。在课程Derived中,我想将foo()公开,bar()私有。下面的代码是正确而自然的方法吗?

class Base {
   public:
     void foo();
     void bar();
};

class Derived : public Base {
   private:
     void bar();
};

7 个答案:

答案 0 :(得分:82)

C ++ '03标准的第11.3节描述了这种能力:

  11.3访问声明
   访问权限   基类的成员可以更改   在派生类中提及它   派生类中的qualified-id   宣言。这样的提及被称为   访问声明。一个人的影响   访问声明qualified-id;是   定义为等同于   声明使用qualified-id

所以有两种方法可以做到。

  

注意:从ISO C ++ '11开始,如注释中所述,禁止访问声明(Base::bar;)。应该使用using声明(using Base::bar;)。

1)您可以使用公共继承,然后将栏设为私有:

class Base {
public:
    void foo(){}
    void bar(){}
};

class Derived : public Base {
private:
    using Base::bar;
};

2)您可以使用私有继承,然后将foo公开:

class Base {
public:
    void foo(){}
    void bar(){}
};

class Derived : private Base {
public:
    using Base::foo;
};

注意:如果你有一个Base类型的指针或引用,它包含Derived类型的对象,那么用户仍然可以调用该成员。

答案 1 :(得分:12)

实际上没有办法做你想做的事,因为如果你从Base公开派生,那么班级的用户将始终能够:

Derived d;
Base& b = d;
b.bar();

使基类中的类派生publicy中的公共基类函数不可访问是“正确或自然的”;相反,应该重构基类接口,使这些函数不公开或分成单独的类。

答案 2 :(得分:8)

首先,您必须从OOP角度了解您想要做什么。有两种完全不同的继承类型:

  1. 接口的继承。当您在Java或其他语言中使用接口作为独立实体执行implement时,当您从C ++中公开继承空抽象类时,也会发生这种情况。在这里你根本不关心代码,但是想告诉你的编译器和每个使用你的基类/派生类的人,这个派生类是你的基类的特殊类型,它具有所有的属性基类,它的行为完全,就像它的用户可见的基类一样,并且可以在任何算法中用来代替基类。

  2. 代码的继承。您在基类中有一段代码要在派生类中重用。基类和派生类不必以任何方式相关,您只想重用代码,就是这样。

  3. C ++中的公共继承是两种类型的混合,您获得了接口继承,并且您也获得了代码继承。私有继承是一种不同类型的野兽,你得到代码继承,派生类的用户不能使用它代替基类,而且从用户的角度来看基础和派生类没什么关系,所以 - 所以-ever。

    struct Base {};
    struct PublicDerived : public Base {};
    struct PrivateDerived: private Base {};
    
    Base * base; PublicDerived * public_derived; PrivateDerived * private_derived;
    
    base = public_derived; //good
    base = private_derived; //compilation error.
    

    由于您想要更改界面,不应该使用公共继承,通过更改界面,您实际上说这两个类具有不同的行为,并且不能互换使用。所以你真正想要的是私下继承,然后制作你想要公开的所有方法,不是相反的方式

答案 3 :(得分:2)

根据Liskov Substitution Principle,公共继承应该模拟“is-a”。您Derived公开继承自Base的内容是,无论何处需要Base对象,Derived类型的对象都会这样做。

如果您要求Derived隐藏一些可用于Base的操作,那么您建模的内容不是“is-a”,而公共继承不是正确的工具。< / p>

你想要的是私人继承或组合,正如其他答案所详述的那样。

答案 4 :(得分:1)

假设你有这个:

class Foo{
public:
    void method1();
    void method2();
    void notGonnaSeeIt();
 private:
    //stuff
 };

要有效地包装它,您可以执行私有继承并将您想要的方法传递给Brian建议的公共声明:

class Bar : private Foo{
    void methodA(){ method1(); }
    void methodB(){ method2(); }
    //more stuff
};

或者你可以用装饰器包装它

template<class T>
class Bar{
public:
    Bar(T *_input) : m_Input(_input){}
    void methodA() { m_Input->method1(); }
    void methodB() { m_Input->method2(); }
    //whatever else you need/want
private:
    T* m_Input;
};

就个人而言,我更喜欢模板方式,因为它允许你对任何继承自Foo的类做同样的事情。

答案 5 :(得分:1)

如果以后不需要将其视为基类,只需要基类的某些函数,那么可以使用组合而不是继承? (C#是我的第一语言,但你明白了)

class Base {
    public void foo();
    public void bar();
};

class Derived {
    private Base _base;

    public void bar() {
        _base.bar();
    }
};

答案 6 :(得分:0)

使用C ++ 11,您可以执行以下操作:

class Base {
   public:
     void foo();
     void bar();
};

class Derived : public Base {
   private:
     using Base::bar;  

};

这确保无法从Derived类外部访问Base :: bar()。它仍然可以从Base类外部访问。

相关问题