我有一个带有一些私有内部的类Widget,但我想通过友谊将这些内部暴露给谓词仿函数(仅限)。
class Widget
{
ComponentA a;
ComponentB b;
friend class WidgetPredicate;
};
class WidgetPredicate : public std::unary_function<bool, const Widget&>
{
bool operator () (const Widget& w) const
{
// inspect a and b and make a yes/no decision
}
};
目的是我可以在所有std :: xxxx_if算法系列中使用WidgetPredicate函数作为sifter。
但是,我想在系统中留下一些可扩展性,未来的开发人员可以制作新的谓词,以某种方式巧妙地提升朋友的地位。这有一个很好的设计习语吗?我目前的(非)解决方案是Widget中的所有内容都是公开的。
我尝试了一个基类,它通过受保护的函数将Widget的内部暴露给WidgetPredicate的子类型,如:
class WidgetPredicate : public std::unary ...
{
protected:
const ComponentA& expose_a ( const Widget& w ) const { return w.a; }
const ComponentB& expose_b ( const Widget& w ) const { return w.b; }
public:
virtual bool operator () ...
};
class DerivedWidgetPredicate : public WidgetPredicate
{
public:
virtual bool operator () (const Widget& w)
{
const ComponentA& a = this->expose_a(w); // a can now be inspected/predicated upon
const ComponentB& b = this->expose_b(w); // b ...
}
};
我可以忍受现在任何一个班级只能通过说:公共WidgetPredicate来检查Widget内部的潜力。我并不是想防范恶意开发人员,所以如果他们说他们是一个友好的WidgetPredicate,那么我愿意从表面上看待它。 语法也很低,但我也可以忍受。我不喜欢维护问题,当我更改Widget的内部时,我还必须向基本谓词添加新的expose()方法。 (IMO该过程可能而且应该是机械的)。
我总是可以直接将暴露方法放在Widget类中,但是IMO在那时我可能会将这些字段公之于众,并且只使用它(即我当前的解决方案)。
答案 0 :(得分:2)
虽然它更昂贵,但您应该定义允许外部代码执行哪些操作并实现它们。如果您不想在公共/受保护的界面中提供这些操作,那么您发布的解决方案(将另一个类声明为friend
并将其用作内部代码的代理)是一个很好的解决方案。
这是主观的,可能是一个不受欢迎的评论,但无论如何......没有用于暴露类内部的良好的设计机制。
&LT;讽刺&gt;只要公开一切&lt; /讽刺&GT;
您正在做的是开发一种复杂的机制来打破您的封装。完成后,所有代码都可以访问您的私人成员。您声明只有谓词仿函数可以访问成员,但是您无法阻止来自谓词类型的派生的非谓词类,只是为了获取对数据的访问权。 / p>
封装的一个要点是减少依赖性:外部代码仅依赖于公共接口,您可以随时更改内部类型和表示,外部代码不会中断(外部代码为not class or friend
)。现在,在您(直接或间接)暴露内部之后,那些现在已成为您公共接口的一部分,因此必须被冻结。
封装的另一个方面是你可以保证内部数据的不变量。在外部代码可以访问内部代码之后,您无法控制方法的任何类型的不变量(比如将容器的max_size
字段保持为获取的内存的大小)并且您的类可能会中断给别人滥用。
友谊不具有传递性或继承性的原因:当您宣布某个班级是您班级的朋友时,您可以检查该班级的行为(在大多数情况下,您完全控制了该班级) 。您知道您提供访问权限的代码不会破坏您自己的代码。
class Widget
{
friend class BackDoor; // assume that you have implemented it
};
class MaliciousClass1 // third class, malicious or not cannot break into Widget
{
};
class MaliciousClass2 : public BackDoor // You cannot block external code from deriving from BackDoor
{
// Can break into your widget, access and modify anything
};
门是敞开的,任何人都可以玩你的私人部分。