【发布时间】:2011-06-21 23:12:37
【问题描述】:
我有一个继承struct A : public B,我想对B隐藏个别功能,这可能吗?
我知道在 A 声明中使用 using BMethod 是可能的。
干杯
【问题讨论】:
-
你想通过这种隐藏达到什么效果?
标签: c++ inheritance using private-members public-fields
我有一个继承struct A : public B,我想对B隐藏个别功能,这可能吗?
我知道在 A 声明中使用 using BMethod 是可能的。
干杯
【问题讨论】:
标签: c++ inheritance using private-members public-fields
如果您想有选择地对 B 隐藏函数,那么首先使用公共继承没有多大意义。
使用私有继承并有选择地将 B 中的方法带入 A 的范围:
struct B{
void method1(){};
void method2(){};
};
struct A : private B{
using B::method1;
};
A a;
a.method1();
a.method2(); //error method2 is not accesible
【讨论】:
这里有一个问题:这将直接违反 Liskov 替换原则,即 A 将不再充当 B。
如果您希望重用B 实现,解决方案就是这样做:
class A
{
public:
void foo() { return b.foo(); }
void bar() { return b.bar(); }
// ...
private:
B b;
};
不要滥用继承,而是使用组合
【讨论】:
using 关键字可用于更改可见性
struct A
{
void method1();
};
struct B: public A
{
void method2();
private:
using A::method1;
};
【讨论】:
除了前面的答案中描述的方式——组合、私有继承和非私有继承,但继承方法声明为私有——另一种方法是显式delete继承方法:
#include <iostream>
struct A {
void foo() { std::cout << "foo\n"; }
};
struct B : A {
void foo() = delete;
};
int main() {
B b;
b.foo(); // COMPILER ERROR
}
虽然b.foo() 调用会产生编译器错误,但客户端代码仍然可以通过使用基类标识符A 限定来调用基类的版本:
b.A::foo(); // compiles, outputs 'foo' to console
当foo 不是A 中的虚拟未删除方法时,这种显式删除方式有效。根据 C++11 标准 §10.3/16,当派生类中的已删除方法覆盖基类的虚拟未删除方法时,此显式删除是错误的。有关此限制的更多信息,请参阅 SO 问题 C++11 Delete Overriden Method 的答案。
【讨论】:
你不能“隐藏”它本身,但你可以让它成为编译时错误来调用它。示例:
struct A
{
void AMethod() {}
};
class B : public A
{
void AMethod() {} //Hides A::AMethod
};
int main()
{
B myB;
myB.AMethod(); //Error: AMethod is private
static_cast<A*>(&myB)->AMethod(); //Ok
return 0;
}
键盘with the error 和without 上的示例。
话虽如此,尽管这是可能的,但你真的不应该这样做。你会把客户搞糊涂的。
编辑:请注意,您也可以使用 virtual functions(和 with the error)来执行此操作。
【讨论】:
virtual,否则不需要定义它。 (我只是懒了,用复制/粘贴来制作B)
对于那些建议组合的人......这可能不是最好的处理方式。我的理解是,Liskov 替换原则仅表明基类中的函数有可能用于子类,而不是它们必须如此。例如,对于特定的基类,您可能有多个函数,它们基本上执行相同的操作,但针对不同的特定情况。在派生类中,您可能希望将这些公共函数抽象出来,以简化用户界面。这是可以使用私有继承的地方。私有继承也可能是必需的,如果我们在基类中有受保护的函数,我们不希望基类的用户调用,但对派生类来说是无价的。
简而言之,如果必须,请使用私有继承,但在大多数情况下首选组合。
【讨论】:
还有另一种方法。
class A{
void f1();
void f2();
void f3();
}
class BInterface{
void f2();
void f3();
}
class B : public A, BInterface
{
}
BInterface b = new B();
b->f1(); //doesn't work since f1 is not declared in BInterface
b->f2(); //should work
b->f3(); //should work
delete(b);
使用 BInterface 作为继承类的过滤器以排除不需要的方法。在这种情况下不违反里氏替换原则,因为 BInterface 类的对象不是 A 类的对象,即使 B 类的对象是 BInterface 类的对象。
【讨论】:
如果方法在 B 中是私有的,那么即使您使用公共继承,它们也会对 a 保持隐藏。
【讨论】:
无法更改原始方法的可见性。
您可以在 struct A 中创建一个具有相同名称的方法并将该方法设为私有方法,但这并不妨碍当 struct A 的实例被以下变量引用时调用该方法输入B。
【讨论】:
为什么不在基类中将其设为 Virtual 并在其子类中覆盖它? (more help)
【讨论】: