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

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

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


class Derived : public Base {
private:
void bar();
};
37527 次浏览

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

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

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

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

11.3 Access 声明
一个 可以更改基类的成员 在派生类中,通过提及它的 派生类中的修饰 -id 声明。这样的提及被称为 访问声明 访问声明修饰的 id; 是 定义为等同于 使用限定 id 的声明

所以有两种方法可以做到这一点。

注意: 从 ISO C + +’11开始,禁止使用访问声明(Base::bar;) ,如注释中所述。应该使用 using-Declaration (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 类型的对象,那么用户仍然可以调用该成员。

假设你有这个:

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继承的任何类做同样的事情。

如果以后不需要把它当作基类,只需要基类的一些函数,那么可以使用组合而不是继承吗?(C # 是我的母语,不过你懂的)

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


class Derived {
private Base _base;


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

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

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

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

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.

因为您希望更改接口,所以 不应该使用公共继承,通过更改接口,您实际上表明这两个类具有不同的行为,不能互换使用。因此,您真正需要的是私有继承,然后使所有您想要的方法为 public 和 而不是反过来

根据 Liskov代换原则,公共继承应该建立“ is-a”模型对于从 Base公开继承的 Derived来说,无论在哪里需要 Base对象,类型为 Derived的对象都可以。

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

您需要的是私有继承或组合,其他答案已经详细说明了这一点。

使用 C + + 11,你可以做到以下几点:

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


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


};

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