C++ 如何从基类公开继承,但在派生类中使基类中的某些公共方法私有?

C++ 如何从基类公开继承,但在派生类中使基类中的某些公共方法私有?,c++,C++,例如,类Base有两个公共方法:foo()和bar()。类派生的继承自类基。在类Derived中,我想将foo()设置为公共,但将bar()设置为私有。下面的代码是正确和自然的方法吗 class Base { public: void foo(); void bar(); }; class Derived : public Base { private: void bar(); }; 实际上没有办法做你想做的事情,因为如果你从Base公开派生,该类的

例如,类
Base
有两个公共方法:
foo()
bar()
。类
派生的
继承自类
。在类
Derived
中,我想将
foo()
设置为公共,但将
bar()
设置为私有。下面的代码是正确和自然的方法吗

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

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

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

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

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

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

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

因此,有两种方法可以做到这一点

注意:如ISO C++ + 11所示,在注释中禁止访问声明(<代码> BAS::Bar;< /Cord>)。应该使用using声明(
使用Base::bar;

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

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类型的指针或引用,其中包含一个派生类型的对象,那么用户仍然可以调用该成员

假设您有:

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;
};
模板
分类栏{
公众:
条(T*_输入):m_输入(_输入){}
void methodA(){m_Input->method1();}
void methodB(){m_Input->method2();}
//你还需要/想要什么
私人:
T*m_输入;
};

就个人而言,我更喜欢模板方式,因为它允许您对从
Foo

继承的任何类执行相同的操作。如果您以后不需要将其视为基类,并且只需要基类的一些函数,您可以使用组合而不是继承?(C#是我的第一语言,但你明白了)


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

  • 接口的继承。当你在Java或其他具有独立实体的接口的语言中执行<代码> >代码时,也会发生在C++中java从空抽象类继承的情况。在这里,您根本不关心代码,而是想告诉您的编译器和使用基类/派生类的所有人,这个派生类是一种特殊的基类,它具有基类的所有属性,它的行为与基类的用户可见的程度完全相同,并且可以在任何算法中代替基类使用

  • 代码的继承。您希望在派生类中重用基类中的一段代码。基类和派生类不必以任何方式相互关联,您只需要重用代码即可

  • C++中的公共继承是两种类型的混合,您得到接口继承,也获得代码继承。私有继承是另一种类型的野兽,你只能得到代码继承,派生类的用户不能用它来代替基类,从用户的角度来看,基类和派生类没有任何关系

    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.
    
    由于您想要更改接口,不应该使用公共继承,通过更改接口,您可以有效地表示这两个类具有不同的行为,不能互换使用。因此,您真正想要的是私下继承,然后将所有您想要的方法公开,而不是反过来

    根据,公共继承应该是“is-a”模型。您所说的
    派生的
    公开继承自
    Base
    是,无论哪里需要
    Base
    对象,类型为
    派生的
    的对象就可以了

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


    正如其他答案所详述的,您想要的是私有继承或组合class Base { public: void foo(); void bar(); }; class Derived : public Base { private: using Base::bar; };

    这确保了不能从派生类外部访问Base::bar()。当然,它仍然可以从基类之外访问。

    -1因为你认为它不能做是错误的,但是+1因为你认为它可能不应该做是正确的。那么通过私有访问进行反向派生,然后将所需函数公开呢?@jamesMcNellis抱歉,我不明白你在说什么,表示Brian R.Bondy给出的答案是错误的?请你给我解释一下。我是
    C++
    +1的学生和新手:这是可以做到的,但它是用来授予访问权限的,而不是限制访问权限的。我只是从语言功能方面选择了这个答案作为公认的答案,不是从ODE最佳实践方面。- 1使用弃用<代码> BAS::FoO < /C> >代替<代码>使用Base::Foo< /Co> > <代码> Base:Foo< /Case>在C++ 03中被弃用了吗?如果它被禁止在C++ 11上,我不理解-- 1,因为答案是
    class Base {
       public:
         void foo();
         void bar();
    };
    
    class Derived : public Base {
       private:
         using Base::bar;  
    
    };