简体   繁体   English

优先将非成员非朋友功能发送给成员函数

[英]Preferring non-member non-friend functions to member functions

This question title is taken from the title of item #23 in Effective C++ 3rd Edition by Scott Meyers. 这个题目标题取自Scott Meyers的Effective C ++ 3rd Edition中第23项的标题。 He uses the following code: 他使用以下代码:

class WebBrowser {
public:
    void clearCache();
    void clearHistory();
    void removeCookies();

    //This is the function in question.
    void clearEverything();
};

//Alternative non-member implementation of clearEverything() member function.
void clearBrowser(WebBrowser& wb) {
    wb.clearCache();
    wb.clearHistory();
    wb.removeCookies();
};

While stating that the alternative non-member non-friend function below is better for encapsulation than the member function clearEverything(). 虽然声明下面的替代非成员非友元函数比成员函数clearEverything()更适合封装。 I guess part of the idea is that there are less ways to access the internal member data for the WebBrowser if there are less member functions providing access. 我想部分想法是,如果提供访问的成员函数较少,则访问WebBrowser的内部成员数据的方法较少。

If you were to accept this and make functions of this kind external, non-friend functions, where would you put them? 如果你接受这个并使这种外部非朋友功能的功能,你会把它们放在哪里? The functions are still fairly tightly coupled to the class, but they will no longer be part of the class. 函数仍然与类紧密耦合,但它们将不再是类的一部分。 Is it good practice to put them in the class's same CPP file, in another file in the library, or what? 将它们放在类的相同CPP文件中,在库中的另一个文件中,或者什么?

I come from a C# background primarily, and I've never shed that yearning for everything to be part of a class, so this bewilders me a little (silly though that may sound). 我主要是来自C#背景,而且我从来没有对所有成为课堂成员的渴望摆脱那种渴望,所以这让我感到有些困惑(虽然听起来可能很傻)。

Usually, you would put them in the associated namespace. 通常,您可以将它们放在关联的命名空间中。 This serves (somewhat) the same function as extension methods in C#. 这(在某种程度上)与C#中的扩展方法有相同的功能。

The thing is that in C#, if you want to make some static functions, they have to be in a class, which is ridiculous because there's no OO going on at all- eg, the Math class. 问题是在C#中,如果你想制作一些静态函数,它们必须在一个类中,这是荒谬的,因为根本没有OO - 例如,Math类。 In C++ you can just use the right tool for this job- a namespace. 在C ++中,您可以使用正确的工具来完成这项工作 - 命名空间。

So clearEverything is a convenience method that isn't strictly necessary. 所以, clearEverything都是一种非常必要的便利方法。 But It's up to you to decide if it's appropriate. 但是由你来决定它是否合适。

The philosophy here is that class definitions should be kept as minimal as possible and only provide one way to accomplish something. 这里的哲学是类定义应尽可能保持最小,并且只提供一种方法来完成某些事情。 That reduces the complexity of your unit testing, the difficulty involved in swapping out the whole class for an alternate implementation, and the number of functions that could need to be overridden by sub-classes. 这降低了单元测试的复杂性,交换替代实现的整个类所涉及的难度,以及可能需要被子类覆盖的函数数量。

In general, you shouldn't have public member functions that only invoke a sequence of other public member functions. 通常,您不应该只使用一系列其他公共成员函数的公共成员函数。 If you do, it could mean either: 1) you're public interface is too detailed/fine-grained or otherwise inappropriate and the functions being called should be made private, or 2) that function should really be external to class. 如果你这样做,它可能意味着:1)你的公共接口太详细/细粒度或其他不合适,被调用的函数应该是私有的,或者2)该函数应该真正在类外部。

Car analogy: The horn is often used in conjunction w/ slamming on your brakes, but it would be silly to add a new pedal/button for that purpose of doing both at once. 汽车类比:喇叭通常与踩刹车一起使用,但添加一个新的踏板/按钮同时做两件事是愚蠢的。 Combining Car.brake() and Car.honk() is a function performed by Driver . Car.brake()Car.honk()是由Driver执行的功能。 However, if a Car.leftHeadLampOn() and Car.rightHeadLampOn() were two separate public methods, it could be an example of excessively fine grained control and the designer should rethink giving Driver a single Car.lightsOn() switch. 然而,如果Car.leftHeadLampOn()Car.rightHeadLampOn()是两个独立的公共方法,它可能是过度细粒度控制的一个例子,设计者应重新考虑给DriverCar.lightsOn()开关。

In the browser example, I tend to agree with Scott Meyers that it should not be a member function. 在浏览器示例中,我倾向于同意Scott Meyers的观点,即它不应该是成员函数。 However, it could also be inappropriate to put it in the browser namespace. 但是,将它放在浏览器命名空间中也可能不合适。 Perhaps it's better to make it a member of the thing controlling Web browser, eg part of a GUI event handler. 也许最好让它成为控制Web浏览器的东西的成员,例如GUI事件处理程序的一部分。 MVC experts feel free to take over from here. MVC专家随时可以从这里接管。

I do this a lot. 我做了很多。 I've always put them into the same .cpp as the other class member functions. 我总是把它们放在与其他类成员函数相同的.cpp中。 I don't think there is any binary size overhead depending where you put them though. 我不认为有任何二进制大小开销取决于你放置它们的位置。 (unless you put it in a header :P) (除非你把它放在标题中:P)

If you want to go down this route the imlementation of clearEverything should be put in both the header (declaration) and implementation of the class - as they are tightly coupled and seems the best place to put them. 如果你想沿着这条路走下去, clearEverything clearEverything的clearEverything应该放在标题(声明)和类的实现中 - 因为它们是紧密耦合的,似乎是放置它们的最佳位置。

However I would be inclined to place them as a part of the class - as in the future you may have other things to clear or there may be a better or faster implementation to implement clearEverything such as droppping a database an just recreate the tables 但是我倾向于将它们作为类的一部分 - 因为将来你可能有其他事情要清除,或者可能有更好或更快的实现来实现clearEverything例如删除数据库并重新创建表

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

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