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

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了私有静态成员函数或匿名命名空间中的自由函数?相关的知识,希望对你有一定的参考价值。

我最近在风格上做了一个改变,想看看其他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成员呢?

你们有什么感想?

答案

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

正如您所说,它减少了依赖关系并可能保存一些重新编译。

另一答案

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

另一答案

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

另一答案

就个人而言,我使用的唯一静态函数是工厂函数,就像这样

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观察到一些函数在成为非成员时不会“感觉”正确,即使他们可能是非朋友的非成员。只有通过平衡许多竞争问题才能找到类的“最佳”接口,其中封装程度只有一个。

不过,这篇文章的教训应该是清楚的。尽管有传统观点,但使用非友元非成员函数可以改进类的封装,并且对成员函数的这些函数的偏好使得设计和开发具有完整且最小(或接近最小)的接口的类变得更容易。关于生成的调用语法的自然性的争论通常是没有根据的,并且对非朋友非成员函数的偏好的采用导致类的接口的打包策略,其最小化客户端编译依赖性,同时最大化它们可用的便利函数的数量。

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

另一答案

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

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

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

另一答案

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

这是我发现的唯一缺点。

另一答案

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

自由功能:

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();
 }

以上是关于私有静态成员函数或匿名命名空间中的自由函数?的主要内容,如果未能解决你的问题,请参考以下文章

自调用匿名函数(匿名闭包)解析与调用

自调用匿名函数(匿名闭包)解析与调用

js---14公有私有成员方法

闭包与内部类

Golang中的匿名函数(闭包)

私有类函数与未命名命名空间中的函数