我正在使用wxWidgets,如果您曾经使用它,您将知道基类中有 lot 的公共函数。我最近遇到了一种情况,我不希望直接从派生类调用方法SetText()
。也就是说,派生类继承了SetText()
函数,但我不希望客户端可以使用此函数。相反,我提供了两个调用SetText()
的新函数,但在执行一些额外操作之前没有。
目前,客户端(我!)可能忘记调用特殊功能,只需拨打SetText()
即可。因此,将不会执行一些额外的操作。这些操作非常微妙,很容易被忽视。
那么,我可以将单个函数标记为私有,以便客户端无法调用它们,或者只是让客户端无法直接调用它们(它们必须使用我的函数间接调用它)?
请注意,SetText()
不虚拟。
编辑:对于遇到此问题的未来程序员,请检查标记的答案和Doug T.'s答案。
答案 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)
您可以通过执行私有继承将每个 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 的工作方式。
您可以通过在派生类中创建私有版本来隐藏SetText
。这仅在通过派生类指针访问时有效,并且在处理基类指针时不提供任何安全性。如果客户端具有基类ptr,则仍将调用基类SetText
。
您可以包装BaseClass
而不是从中派生,并公开您想要的界面。根据您的代码的工作方式,这可能也可能不存在。如果您想要正常界面但稍微改变一下,那么您将不得不重新实现要转发到BaseClass
的每个功能。
您可以从第二个接口继承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派生类中的方法,可以重定向或(如果需要额外的参数或其他内容)错误。