此问题标题取自Scott Meyers的Effective C ++ 3rd Edition中第23项的标题。他使用以下代码:
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();
};
虽然声明下面的替代非成员非友元函数比成员函数clearEverything()更适合封装。我想部分想法是,如果提供访问的成员函数较少,则访问WebBrowser的内部成员数据的方法较少。
如果您接受此功能并制作此类外部非朋友功能的功能,您会将它们放在哪里?函数仍然与类紧密耦合,但它们将不再是类的一部分。将它们放在类的相同CPP文件中,在库中的另一个文件中,或者是什么时,这是一种好习惯吗?
我主要是来自C#背景,而且我从来没有对所有成为课堂成员的渴望摆脱那种渴望,所以这让我感到困惑(虽然听起来很傻)。
答案 0 :(得分:1)
通常,您可以将它们放在关联的命名空间中。这(在某种程度上)与C#中的扩展方法有相同的功能。
问题是在C#中,如果你想制作一些静态函数,它们必须在一个类中,这是荒谬的,因为根本没有OO - 例如,Math类。在C ++中,您可以使用正确的工具来完成这项工作 - 命名空间。
答案 1 :(得分:1)
所以clearEverything
是一种非常必要的便捷方法。但是由你来决定它是否合适。
这里的哲学是类定义应尽可能保持最小化,并且只提供一种方法来完成某些事情。这降低了单元测试的复杂性,交换替代实现的整个类所涉及的难度,以及可能需要被子类覆盖的函数数量。
通常,您不应该只使用一系列其他公共成员函数的公共成员函数。如果你这样做,它可能意味着:1)你的公共接口太详细/细粒度或其他不合适,被调用的函数应该是私有的,或者2)该函数应该真正在类外部。
汽车类比:喇叭通常与踩刹车一起使用,但添加一个新的踏板/按钮同时进行这两个操作是愚蠢的。结合Car.brake()
和Car.honk()
是由Driver
执行的功能。但是,如果Car.leftHeadLampOn()
和Car.rightHeadLampOn()
是两个单独的公共方法,则可能是过度细粒度控制的示例,设计人员应重新考虑提供Driver
a单Car.lightsOn()
开关。
在浏览器示例中,我倾向于同意Scott Meyers的观点,即它不应该是成员函数。但是,将它放在浏览器命名空间中也可能不合适。也许最好让它成为控制Web浏览器的东西的成员,例如GUI事件处理程序的一部分。 MVC专家随时可以从这里接管。
答案 2 :(得分:0)
我做了很多。我总是把它们放在与其他类成员函数相同的.cpp中。我不认为有任何二进制大小开销取决于你放置它们的位置。 (除非你把它放在标题中:P)
答案 3 :(得分:0)
如果你想沿着这条路走下去,clearEverything
的实现应该放在标题(声明)和类的实现中 - 因为它们是紧密耦合的,似乎是放置它们的最佳位置。 / p>
但是,我倾向于将它们作为课程的一部分 - 因为将来您可能还有其他事情要清除,或者可能有更好或更快的实现来实现clearEverything
,例如删除数据库只是重新创建表格