繁体   English   中英

我应该何时更喜欢非会员非朋友功能到会员功能?

[英]When should I prefer non-member non-friend functions to member functions?

Meyers在他的书“Effective C ++”中提到,在某些情况下,非成员非朋友函数比成员函数更好地封装。

例:

// Web browser allows to clear something
class WebBrowser {
public:
  ...
  void clearCache();
  void clearHistory();
  void removeCookies();
  ...
};

许多用户希望一起执行所有这些操作,因此WebBrowser可能还提供了一个功能:

class WebBrowser {
public:
  ...
  void clearEverything();  // calls clearCache, clearHistory, removeCookies
  ...
};

另一种方法是定义非成员非朋友函数。

void clearBrowser(WebBrowser& wb)
{
  wb.clearCache();
  wb.clearHistory();
  wb.removeCookies();
}

非成员函数更好,因为“它不会增加可以访问类的私有部分的函数的数量。”,从而导致更好的封装。

clearBrowser这样的函数便利函数,因为它们无法提供WebBrowser客户端无法以其他方式获得的任何功能。 例如,如果clearBrowser不存在,客户端可以只调用clearCacheclearHistoryremoveCookies本身。

对我而言, 便利功能的例子是合理的。 但是当非会员版本擅长时,除了便利功能之外还有其他例子吗?

更一般地说, 什么时候使用哪些规则

更一般地说, 什么时候使用哪些规则?

以下是Scott Meyer的规则( 来源 ):

Scott有一篇有趣的文章,主张非成员非朋友函数改进了类的封装。 他使用以下算法来确定函数f的放置位置:

 if (f needs to be virtual) make fa member function of C; else if (f is operator>> or operator<<) { make fa non-member function; if (f needs access to non-public members of C) make fa friend of C; } else if (f needs type conversions on its left-most argument) { make fa non-member function; if (f needs access to non-public members of C) make fa friend of C; } else if (f can be implemented via C's public interface) make fa non-member function; else make fa member function of C; 

他对封装的定义涉及私有数据成员更改时受影响的函数数量。

在我看来,这几乎总结了一切,这也很合理。

我经常选择在我的类之外构建实用程序方法,因为它们是特定于应用程序的。

应用程序通常处于不同的环境中,然后是引擎完成下面的工作。 如果我们以网络浏览器为例,3个明确的方法属于Web引擎,因为这是其他任何地方难以实现的功能,但ClearEverything()肯定更具针对性。 在这种情况下,您的应用程序可能会有一个小对话框,其中包含一个清除所有按钮,以帮助用户提高效率。 也许这不是另一个应用程序重新使用您的Web浏览器引擎想要做的事情,因此在引擎类中使用它会更加混乱。

另一个例子是数学图书馆。 通常,将平均值或标准派生等更高级的功能作为数学类的一部分实现是有意义的。 但是,如果您有一种特定于应用程序的方法来计算某些非标准版本的均值,则它应该在您的类之外,并且应该是特定于您的应用程序的实用程序库的一部分。

我从来不是强大的硬编码规则的忠实粉丝,以这种或那种方式实现事物,这通常是意识形态和原则的问题。

M.

当库的开发人员想要编写可以在具有类类型的任一参数上重载的二元运算符时,通常使用非成员函数,因为如果使它们成为类的成员,则只能在第二个参数上重载(首先是隐含的那个类的对象)。 complex各种算术运算符可能是这方面的明确例子。

在你引用的例子中,动机是另一种: 使用仍然允许你完成工作的最小耦合设计

这意味着虽然clearEverything都可以(而且,坦率地说,很可能)成为一个成员,但我们不会将其作为一个,因为它在技术上不是必须的。 这给你买了两件东西:

  1. 您不必承担在公共界面中使用clearEverything方法的责任(一旦您携带一个方法,您终身嫁给它)。
  2. 可以访问类的private成员的函数数量较少,因此将来的任何更改都将更容易执行,并且不太可能导致错误。

也就是说,在这个特殊的例子中,我觉得这个概念已经走得太远了,对于这种“无辜”的功能,我倾向于让它成为一个成员。 但这个概念是合理的,而在“现实世界”的情况下,事情并非如此简单,它会更有意义。

在保持封装的同时允许类提供“足够”功能的位置是一些需要考虑的事项。

如果WebBrowser在许多地方重用,则依赖关系/客户端可以定义多个便利功能。 这使您的类( WebBrowser )轻量级且易于管理。

相反的是, WebBrowser最终取悦了所有客户端,并且变成了一些难以改变的单片兽。

一旦在多种场景中使用该类,您是否发现该类缺乏功能? 您的便利功能中是否出现了模式? 最好(IMO)推迟正式扩展类的接口,直到模式出现并且有充分的理由添加此功能。 最小的类更易于维护,但您不希望在整个地方进行冗余实施,因为这会将维护负担推到客户端上。

如果您的便利功能实现起来很复杂,或者存在可以显着提高性能的常见情况(例如,使用一个锁清空线程安全集合,而不是每次锁定一个元素),那么您也可以我想考虑那个案子。

还有一些情况,当您使用它时,您会发现WebBrowser确实遗漏了某些内容。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM