命名空间+函数与类上的静态方法

Rob*_*rtL 268 c++ static-methods namespaces

假设我已经或即将编写一组相关函数.假设他们与数学有关.在组织上,我应该:

  1. 编写这些函数并将它们放在我的MyMath命名空间中并通过它们引用它们MyMath::XYZ()
  2. 创建一个名为的类MyMath,并将这些方法设为静态,并引用类似的方法MyMath::XYZ()

为什么我会选择一个作为组织我的软件的方法?

pae*_*bal 227

默认情况下,使用命名空间函数.

类是构建对象,而不是替换名称空间.

在面向对象的代码中

Scott Meyers为他的有效C++书籍写了一篇关于这个主题的整篇文章,"将非成员非朋友函数推荐给成员函数".我在Herb Sutter的一篇文章中找到了这个原则的在线参考:http://www.gotw.ca/gotw/084.htm

重要的是要知道:在与类相同的命名空间中的C++函数属于该类的接口(因为ADL将在解析函数调用时搜索这些函数).

命名空间函数,除非声明为"friend",否则无法访问类的内部,而静态方法则具有.

这意味着,例如,在维护课程时,如果您需要更改课程的内部,则需要在其所有方法中搜索副作用,包括静态方法.

扩展我

将代码添加到类的接口.

在C#中,即使您无法访问它,也可以向类添加方法.但在C++中,这是不可能的.

但是,仍然在C++中,您仍然可以添加命名空间函数,甚至可以添加给某人为您编写的类.

从另一方面看,这在设计代码时很重要,因为通过将函数放在命名空间中,您将授权用户增加/完成类的界面.

扩展II

前一点的副作用是,不可能在多个标头中声明静态方法.每个方法都必须在同一个类中声明.

对于名称空间,可以在多个标头中声明来自同一名称空间的函数(几乎标准的交换函数就是最好的例子).

延期三

命名空间的基本功能是在某些代码中,如果使用关键字"using",则可以避免提及它:

#include <string>
#include <vector>

// Etc.
{
   using namespace std ;
   // Now, everything from std is accessible without qualification
   string s ; // Ok
   vector v ; // Ok
}

string ss ; // COMPILATION ERROR
vector vv ; // COMPILATION ERROR
Run Code Online (Sandbox Code Playgroud)

你甚至可以将"污染"限制在一个类别:

#include <string>
#include <vector>

{
   using std::string ;
   string s ; // Ok
   vector v ; // COMPILATION ERROR
}

string ss ; // COMPILATION ERROR
vector vv ; // COMPILATION ERROR
Run Code Online (Sandbox Code Playgroud)

这种"模式"对于正确使用几乎标准的交换习惯是必需的.

这对于类中的静态方法是不可能的.

因此,C++命名空间有自己的语义.

但它更进一步,因为您可以以类似于继承的方式组合名称空间.

例如,如果您具有带有函数AAA的命名空间A,带有函数BBB的命名空间B,则可以声明命名空间C,并使用关键字using在此命名空间中引入AAA和BBB.

结论

命名空间用于命名空间.类适用于类.

C++的设计使得每个概念都不同,并且在不同的情况下以不同的方式使用,作为解决不同问题的方法.

需要名称空间时不要使用类.

在您的情况下,您需要名称空间.

  • @dashesy:*名称空间与静态方法*与线程无关,因此,名称空间更好,因为名称空间几乎总是比静态方法更好。静态方法可以访问类成员变量,因此它们的封装值比名称空间低。在线程执行中,隔离数据甚至更为重要。 (3认同)

Dan*_*Tao 53

有很多人会反对我,但这就是我的看法:

类本质上是某种对象的定义.静态方法应定义与该对象定义密切相关的操作.

如果你只是想要一组与底层对象或一种对象的定义无关的相关函数,那么我会说只使用命名空间.就我而言,从概念上讲,这是更明智的.

例如,在您的情况下,问自己,"什么是MyMath?" 如果MyMath没有定义一种对象,那么会说:不要把它变成一个类.

但就像我说的那样,我知道有很多人会(甚至激烈地)不同意我(特别是Java和C#开发人员).

  • 这是因为Jave和C#人没有选择权. (55认同)
  • @ shog9.你也可以模板化功能! (7认同)
  • @Dan:大概是需要数学例程并希望支持"插入"不同实现的人. (6认同)
  • 你对此有一个非常纯粹的观点.但实际上,使用全静态方法的类可以派上用场:你可以`typedef`它们,将它们用作模板参数等. (3认同)

Sho*_*og9 16

  • 如果需要静态数据,请使用静态方法.
  • 如果它们是模板函数,并且您希望能够为所有函数指定一组模板参数,那么在模板类中使用静态方法.

否则,使用命名空间函数.


回应评论:是的,静态方法和静态数据往往被过度使用.这就是为什么我只提供两个相关场景,我认为它们可以提供帮助.在OP的具体示例(一组数学例程)中,如果他希望能够指定适用于所有例程的参数(例如,核心数据类型和输出精度),他可能会执行以下操作:

template<typename T, int decimalPlaces>
class MyMath
{
   // routines operate on datatype T, preserving at least decimalPlaces precision
};

// math routines for manufacturing calculations
typedef MyMath<double, 4> CAMMath;
// math routines for on-screen displays
typedef MyMath<float, 2> PreviewMath;
Run Code Online (Sandbox Code Playgroud)

如果您不需要,那么一定使用命名空间.

  • 所谓的静态数据可以是命名空间的实现文件中的命名空间级别数据,这样可以减少耦合,因为它不必显示在标题中. (2认同)

cop*_*pro 12

您应该使用命名空间,因为命名空间比类具有许多优点:

  • 您不必在同一标头中定义所有内容
  • 您不需要在标头中公开所有实现
  • 你不能using成为班级成员; 你可以using命名空间成员
  • 你不能using class,但using namespace不是所有这一切都是一个好主意
  • 使用类意味着在没有类时会创建一些对象

在我看来,静态成员非常过度使用.在大多数情况下,它们不是真正的必需品.静态成员函数可能更适合作为文件范围函数,而静态数据成员只是具有更好,不当信誉的全局对象.

  • "您不需要在标题中公开所有实现",而不是在使用类时也不会这样做. (3认同)
  • @Vanuan:编译器在使用`inline`时只保证一件事,它不是"内联"函数体.`inline`的*real*(并由标准保证)目的是防止多个定义.阅读C++的"一个定义规则".此外,由于预编译的头问题而不是ODR问题,链接的SO问题未编译. (2认同)

alf*_*lfC 5

我想总结一下并补充到其他答案中。另外,我的观点是仅限标题的世界。

\n
\n

命名空间

\n

优点:

\n
    \n
  • 命名层次结构的简单解决方案
  • \n
  • 它们不带有任何语义,因此更容易阅读
  • \n
  • 可以存在于不同的文件(标头)中
  • \n
  • 可以延长
  • \n
  • 日常生活活动能力
  • \n
  • 可以定义快捷方式 ( using)。
  • \n
  • 很好地应对操作员过载
  • \n
  • 可用于品牌推广(您可以设计代码并在其上放置命名空间,无需太多)
  • \n
\n

缺点:

\n
    \n
  • 一切都是公开的
  • \n
  • 私有的东西需要未命名的命名空间,所以它不是显式的
  • \n
  • ADL(是的,有些人鄙视ADL)
  • \n
  • 可以扩展(这可能是一件坏事,特别是与 ADL 结合使用,现有代码的语义可以通过扩展命名空间来改变)
  • \n
  • 函数需要按照使用顺序定义(或声明)
  • \n
\n
\n

具有静态方法的类

\n

优点:

\n
    \n
  • 可以有私有组件(函数、变量)并且它们被显式标记。
  • \n
  • 班级可以加好友
  • \n
  • 可以类型参数化(模板)
  • \n
  • 可以是模板参数本身
  • \n
  • 可以实例化
  • \n
  • 可以传递给函数(默认情况下,静态函数的行为类似于非静态方法)。
  • \n
  • 更容易找到模式并从独立函数组中将它们转换为适当的类(最终具有非静态成员)
  • \n
  • 类之间的依赖关系被明确定义
  • \n
  • 函数(静态方法)可以按任何顺序定义
  • \n
\n

缺点:

\n
    \n
  • 无日常生活活动能力
  • \n
  • 不能延长
  • \n
  • 到处都需要关键字 static (有机会取笑该语言)
  • \n
  • 仅仅解决命名问题就有点矫枉过正了。在这种情况下很难阅读。
  • \n
  • 函数(静态方法)始终需要限定 ( myclassspace::fun)。无法声明快捷方式 ( using)。
  • \n
  • 对于操作员过载几乎没有用,需要复杂的朋友机制。
  • \n
  • 不能用于品牌推广。
  • \n
  • ; 你需要记住以:)结尾
  • \n
\n

总之,具有静态方法的类是更好的代码单元,并且允许更多的元编程,并且除了 ADL 和一些语法怪癖之外,可以复制命名空间的所有功能,但有时它们可​​能有点过头了。

\n

像 Bloomberg 这样的公司更喜欢类而不是命名空间。\n如果您不喜欢 ADL 或运算符重载,那么具有静态方法的类是最佳选择。

\n

IMO,如果命名空间和类集成为同一枚硬币的两面,那就太好了。\n例如,如果方法默认是静态的,则将语言中的命名空间标识为类。\n然后能够将它们用作模板参数。\n我不确定如何使用 ADL(可能它可能仅限于符号运算符函数,例如operatorX,这首先是运算符重载和 ADL 的原始动机)

\n