简体   繁体   English

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

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

Meyers mentioned in his book Effective C++ that in certain scenarios non-member non-friend functions are better encapsulated than member functions. Meyers在他的书“Effective C ++”中提到,在某些情况下,非成员非朋友函数比成员函数更好地封装。

Example: 例:

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

Many users will want to perform all these actions together, so WebBrowser might also offer a function to do just that: 许多用户希望一起执行所有这些操作,因此WebBrowser可能还提供了一个功能:

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

The other way is to define a non-member non-friend function. 另一种方法是定义非成员非朋友函数。

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

The non-member function is better because "it doesn't increase the number of functions that can access the private parts of the class.", thus leading to better encapsulation. 非成员函数更好,因为“它不会增加可以访问类的私有部分的函数的数量。”,从而导致更好的封装。

Functions like clearBrowser are convenience functions because they can't offer any functionality a WebBrowser client couldn't already get in some other way. clearBrowser这样的函数便利函数,因为它们无法提供WebBrowser客户端无法以其他方式获得的任何功能。 For example, if clearBrowser didn't exist, clients could just call clearCache , clearHistory , and removeCookies themselves. 例如,如果clearBrowser不存在,客户端可以只调用clearCacheclearHistoryremoveCookies本身。

To me, the example of convenience functions is reasonable. 对我而言, 便利功能的例子是合理的。 But is there any example other than convenience function when non-member version excels? 但是当非会员版本擅长时,除了便利功能之外还有其他例子吗?

More generally, what are the rules of when to use which ? 更一般地说, 什么时候使用哪些规则

More generally, what are the rules of when to use which? 更一般地说, 什么时候使用哪些规则?

Here is what Scott Meyer's rules are ( source ): 以下是Scott Meyer的规则( 来源 ):

Scott has an interesting article in print which advocates that non-member non-friend functions improve encapsulation for classes. Scott有一篇有趣的文章,主张非成员非朋友函数改进了类的封装。 He uses the following algorithm to determine where a function f gets placed: 他使用以下算法来确定函数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; 

His definition of encapsulation involves the number of functions which are impacted when private data members are changed. 他对封装的定义涉及私有数据成员更改时受影响的函数数量。

Which pretty much sums it all up, and it is quite reasonable as well, in my opinion. 在我看来,这几乎总结了一切,这也很合理。

I often choose to build utility methods outside of my classes when they are application specific. 我经常选择在我的类之外构建实用程序方法,因为它们是特定于应用程序的。

The application is usually in a different context then the engines doing the work underneath. 应用程序通常处于不同的环境中,然后是引擎完成下面的工作。 If we take you example of a web browser, the 3 clear methods belongs to the web engine as this is needed functionality that would be difficult to implement anywhere else, however, the ClearEverything() is definitely more application specific. 如果我们以网络浏览器为例,3个明确的方法属于Web引擎,因为这是其他任何地方难以实现的功能,但ClearEverything()肯定更具针对性。 In this instance your application might have a small dialog that has a clear all button to help the user be more efficient. 在这种情况下,您的应用程序可能会有一个小对话框,其中包含一个清除所有按钮,以帮助用户提高效率。 Maybe this is not something another application re-using your web browser engine would want to do and therefor having it in the engine class would just be more clutter. 也许这不是另一个应用程序重新使用您的Web浏览器引擎想要做的事情,因此在引擎类中使用它会更加混乱。

Another example is a in a mathematic libraries. 另一个例子是数学图书馆。 Often it make sense to have more advanced functionality like mean value or standard derivation implemented as part of a mathematical class. 通常,将平均值或标准派生等更高级的功能作为数学类的一部分实现是有意义的。 However, if you have an application specific way to calculate some type of mean that is not the standard version, it should probably be outside of your class and part of a utility library specific to you application. 但是,如果您有一种特定于应用程序的方法来计算某些非标准版本的均值,则它应该在您的类之外,并且应该是特定于您的应用程序的实用程序库的一部分。

I have never been a big fan of strong hardcoded rules to implement things in one way or another, it's often a matter of ideology and principles. 我从来不是强大的硬编码规则的忠实粉丝,以这种或那种方式实现事物,这通常是意识形态和原则的问题。

M. M.

Non-member functions are commonly used when the developer of a library wants to write binary operators that can be overloaded on either argument with a class type, since if you make them a member of the class you can only overload on the second argument (the first is implicitly an object of that class). 当库的开发人员想要编写可以在具有类类型的任一参数上重载的二元运算符时,通常使用非成员函数,因为如果使它们成为类的成员,则只能在第二个参数上重载(首先是隐含的那个类的对象)。 The various arithmetic operators for complex are perhaps the definitive example for this. complex各种算术运算符可能是这方面的明确例子。

In the example you cite, the motivation is of another kind: use the least coupled design that still allows you to do the job . 在你引用的例子中,动机是另一种: 使用仍然允许你完成工作的最小耦合设计

This means that while clearEverything could (and, to be frank, would be quite likely to) be made a member, we don't make it one because it does not technically have to be. 这意味着虽然clearEverything都可以(而且,坦率地说,很可能)成为一个成员,但我们不会将其作为一个,因为它在技术上不是必须的。 This buys you two things: 这给你买了两件东西:

  1. You don't have to accept the responsibility of having a clearEverything method in your public interface (once you ship with one, you 're married to it for life). 您不必承担在公共界面中使用clearEverything方法的责任(一旦您携带一个方法,您终身嫁给它)。
  2. The number of functions with access to the private members of the class is one lower, hence any changes in the future will be easier to perform and less likely to cause bugs. 可以访问类的private成员的函数数量较少,因此将来的任何更改都将更容易执行,并且不太可能导致错误。

That said, in this particular example I feel that the concept is being taken too far, and for such an "innocent" function I 'd gravitate towards making it a member. 也就是说,在这个特殊的例子中,我觉得这个概念已经走得太远了,对于这种“无辜”的功能,我倾向于让它成为一个成员。 But the concept is sound, and in "real world" scenarios where things are not so simple it would make much more sense. 但这个概念是合理的,而在“现实世界”的情况下,事情并非如此简单,它会更有意义。

Locality and allowing the class to provide 'enough' features while maintaining encapsulation are some things to consider. 在保持封装的同时允许类提供“足够”功能的位置是一些需要考虑的事项。

If WebBrowser is reused in many places, the dependencies/clients may define multiple convenience functions. 如果WebBrowser在许多地方重用,则依赖关系/客户端可以定义多个便利功能。 This keeps your classes ( WebBrowser ) lightweight and easy to manage. 这使您的类( WebBrowser )轻量级且易于管理。

The inverse would be that the WebBrowser ends up pleasing all clients, and just becomes some monolithic beast that is difficult to change. 相反的是, WebBrowser最终取悦了所有客户端,并且变成了一些难以改变的单片兽。

Do you find the class is lacking functionality once it has been put to use in multiple scenarios? 一旦在多种场景中使用该类,您是否发现该类缺乏功能? Do patterns emerge in your convenience functions? 您的便利功能中是否出现了模式? It's best (IMO) to defer formally extending the class's interface until patterns emerge and there is a good reason to add this functionality. 最好(IMO)推迟正式扩展类的接口,直到模式出现并且有充分的理由添加此功能。 A minimal class is easier to maintain, but you don't want redundant implementations all over the place because that pushes the maintenance burden onto your clients. 最小的类更易于维护,但您不希望在整个地方进行冗余实施,因为这会将维护负担推到客户端上。

If your convenience functions are complex to implement, or there is a common case which can improve performance significantly (eg to empty a thread safe collection with one lock, rather than one element at a time with a lock each time), then you may also want to consider that case. 如果您的便利功能实现起来很复杂,或者存在可以显着提高性能的常见情况(例如,使用一个锁清空线程安全集合,而不是每次锁定一个元素),那么您也可以我想考虑那个案子。

There will also be cases where you realize something is genuinely missing from the WebBrowser as you use it. 还有一些情况,当您使用它时,您会发现WebBrowser确实遗漏了某些内容。

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

相关问题 有效的C ++项目23首选非成员非友函数比成员函数 - Effective C++ Item 23 Prefer non-member non-friend functions to member functions 优先将非成员非朋友功能发送给成员函数 - Preferring non-member non-friend functions to member functions 非会员非朋友功能与私人功能 - Non-member non-friend functions vs private functions 大规模使用Meyer的建议更喜欢非会员,非朋友的功能? - Large scale usage of Meyer's advice to prefer Non-member,non-friend functions? 非朋友,非成员函数会增加封装? - Non-friend, non-member functions increase encapsulation? 支持Scott Meyer建议的C ++ IDE:优先选择成员之外的非成员非朋友功能 - C++ IDE that supports Scott Meyer's advice: Prefer non-member non-friend functions over members 使用非成员非友元函数代替成员函数:缺点? - Using non-member non-friend functions instead of member functions: disadvantages? 非成员非友元函数真的增加了封装性吗? - Do non-member non-friend functions really increase encapsulation? Scott Meyers建议偏爱非成员非朋友方法是否适用于对象构建? - Does Scott Meyers's advice to prefer non-member non-friend methods apply to object construction? 非成员非朋友函数语法 - non-member non-friend function syntax
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM