2011-09-21 116 views
0

此问题标题取自Scott Meyers的Effective C++第3版中的项目#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#背景,而且我从未摆脱过对所有东西都渴望成为一个类的一部分的渴望,所以这使我感到有些困惑(虽然听起来很傻)。

回答

1

通常,你会把它们放在关联的命名空间中。这有点像C#中的扩展方法。

问题是,在C#中,如果你想制作一些静态函数,它们必须在一个类中,这很荒谬,因为根本没有OO - 例如Math类。在C++中,您可以使用正确的工具来完成这项工作 - 命名空间。

0

我做了很多。我一直把它们放到与其他类成员函数相同的.cpp文件中。我不认为有任何二进制大小的开销,取决于你把它们放在哪里。 (除非你把它放在标题中:P)

0

如果你想沿着这条路走下去,clearEverything应该放在头文件(声明)和类的实现中,因为它们紧密耦合,似乎是放置它们的最佳位置。

但是我会倾向于将它们作为类的一部分 - 因为将来您可能有其他事情要清除,或者可能有更好或更快的实现来实现clearEverything,例如丢弃数据库并重新创建表

+1

如果您发现稍后需要它们,您可以随时将其添加到课程中,但无法删除它们。如果你不需要'clearEverything()'来访问类内部,就把它放在外面。如果让它访问内部变得很重要,那么为这个类编写一个成员函数(并且可以选择'clearEverything()'来调用它)。 –

1

所以clearEverything是一种非常必要的便利方法。但是由您决定是否合适。

这里的哲学是类定义应尽可能最小化,只提供一种方法来完成某些事情。这样可以降低单元测试的复杂性,替换替代实现中涉及的全部类的难度,以及可能需要由子类覆盖的函数的数量。

一般而言,您不应该具有仅调用其他公共成员函数序列的公共成员函数。如果你这样做,这可能意味着:1)你的公共接口过于细致/细化或者不适当,被调用的函数应该是私有的,或者2)该函数应该是真正的类外部的。

汽车比喻:喇叭通常与您的刹车一起使用,但为了同时进行这两种操作,添加一个新的踏板/按钮是很愚蠢的。结合Car.brake()Car.honk()是由Driver执行的功能。但是,如果Car.leftHeadLampOn()Car.rightHeadLampOn()是两个单独的公共方法,则它可能是过度细化控制的示例,并且设计人员应该重新考虑给予Driver单个Car.lightsOn()开关。

在浏览器示例中,我倾向于同意Scott Meyers的看法,认为它不应该是成员函数。但是,将其放入浏览器名称空间也可能不合适。也许最好让它成为控制Web浏览器的东西的一员,例如GUI事件处理程序的一部分。 MVC专家随时可以从这里接管。

+0

已投票。我会告诉你斯科特的想法,处理它在哪里。他提到stdc库如何通过将这些辅助函数添加到不同的.cpp/.h文件来执行相同的操作,并且#include只是您需要的那些函数。 – Eric