私有静态成员函数或匿名命名空间中的自由函数?

时间:2011-07-06 14:40:35

标签: c++ function static namespaces

我最近在风格上做了一个改变,想看看其他c ++程序员对它的感受以及是否有任何缺点。

基本上,当我需要一个不需要访问给定类成员的实用函数时,我以前做的是这样的:

file.h

class A {
public:
    // public interface
private:
    static int some_function(int);
};

file.cpp

int A::some_function(int) {
    // ...
}

但最近,我更喜欢做更像这样的事情:

file.cpp

namespace {
    int some_function(int) {

    }
}
// the rest of file.cpp

这是我的思考过程:

  • 编辑
  • 的文件少了一个
  • 只需在头文件中列出该功能即可提示实现细节 没有必要暴露(即使没有公开)。
  • 如果函数的原型需要更改,则只需要重新编译一个文件。

最后一个对我来说是最引人注目的。所以我的问题是:这有什么缺点吗?

对于我能想到的大多数目的而言,它们在功能上是等效的。在我看来,private static函数几乎总是可以转换为匿名namespace中的自由函数。

编辑:我想到的一件事是private static函数如果有一个指向要操作的对象的指针,则可以访问private个成员,但是如果在这种情况下,为什么不让它成为非static成员?

你们有什么想法?

7 个答案:

答案 0 :(得分:22)

如果该功能仅用于一个源文件,那么在那里定义它是完全合理的。如果没有其他人在使用它,它就不属于标题。

正如你所说,它减少了依赖关系并且可以节省一些重新编译。

答案 1 :(得分:7)

几年前我开始这样做,从未发现任何真正的退缩。对象使用的任何东西,但本身不会改变对象的状态而不需要在其他任何地方使用,我喜欢在实现文件中放入一个匿名命名空间。

答案 2 :(得分:5)

我无法看到使用匿名命名空间的任何缺点。如果可以在不访问类成员的情况下有用地编写函数代码,那么你应该,因为它将它与类本身分离(就像标准算法如何在迭代器对上工作一样)。

答案 3 :(得分:5)

就个人而言,我使用的唯一静态函数是工厂函数,比如

class Angle {
public:
    static Angle FromDegree (float v);
    static Angle FromRadians (float v);

    ...
private:
    Angle (float degree);
};

任何不需要私人访问的东西都是免费功能。如果可能的话,任何不属于公共界面的东西都不会放在公共场所(符合您的新方法)。

Scott Meyer的文章"How Non-Member Functions Improve Encapsulation"大致描述了相同的方法:

  

极小和封装

     

在Effective C ++中,我主张完整且极简的类接口。这样的接口允许类客户端做他们可能合理想做的任何事情,但类不包含比绝对必要的更多的成员函数。我写道,添加超出让客户完成工作所需的最低限度的功能会降低类的可理解性和可维护性,并且会增加客户端的编译时间。 Jack Reeves写道,除了那些真正需要的成员函数之外,它们违反了开放/封闭原则,产生了胖类接口,并最终导致软件腐烂。这是用于最小化类中成员函数数量的相当多的参数,但现在我们还有另外一个原因:如果不这样做会减少类的封装。

     

当然,最小类接口不一定是最好的接口。我在Effective C ++中评论说,如果能够显着提高类的性能,使类更易于使用或防止可能的客户端错误,那么添加超出真正必要的功能可能是合理的。基于他对各种类似字符串的类的工作,Jack Reeves观察到一些函数在成为非成员时不会“感觉”正确,即使他们可能是非朋友的非成员。只有通过平衡许多竞争问题才能找到类的“最佳”接口,其中封装程度只有一个。

     

但是,这篇文章的教训应该是清楚的。尽管有传统观点,但使用非友元非成员函数可以改进类的封装,并且对成员函数的这些函数的偏好使得设计和开发具有完整且最小(或接近最小)的接口的类变得更容易。关于所产生的调用语法的自然参数一般是没有根据的,和通过非朋友非成员函数的偏爱会导致包装策略一类的界面,最大限度地减少客户端的编译依赖,同时最大限度的提供给他们的方便功能的数量。

     

现在是时候放弃传统但不准确的想法,即面向对象意味着什么。你是一个真正的封装信徒吗?如果是这样,我知道你会以他们应得的热情接纳非朋友的非会员职能。

答案 4 :(得分:4)

私有静态非const 变量对于不在.cpp中的任何代码都是无用的,所以我总是使用这样的匿名命名空间。

静态const变量可以记录对客户端代码有用的约束和期望,因此它们位于标题中。

静态函数可能需要访问私有数据成员,因此如果必须,它们会进入标题

答案 5 :(得分:0)

如果您正在使用统一构建(即#include项目的所有.cpp文件到一个编译单元以加快编译时间),您将冒险与其他函数发生名称冲突匿名命名空间。

这是我发现的唯一缺点。

答案 6 :(得分:-1)

静态函数与全局函数相反的全部原因是它访问类的私有成员。如果不是这样,请使用免费功能。在我们有三种替代方法之前,这种分析并不是完整的答案:

自由功能:

void f() { /* cannot access private members of any class */ }

静态功能:

class A {
public:
   static void g() { /* can access private members of class A */ }
};

朋友的功能:

    class A {
    public:
       friend void h();
    };
    class B {
    public:
       friend void h();
   };
   void h() { /* can access private members of both class A and class B */ }

c ++如何做到的真正问题是函数调用看起来不同:

int main() {
   f();
   A::g();
   h();
 }