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

时间:2009-09-16 19:15:02

标签: c++ namespaces static-methods

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

  1. 编写这些函数并将它们放在我的MyMath命名空间中,并通过MyMath::XYZ()
  2. 引用它们
  3. 创建一个名为MyMath的类,并将这些方法设为静态,并引用类似的MyMath::XYZ()
  4. 为什么我会选择其中一种作为组织我的软件的方法?

8 个答案:

答案 0 :(得分:221)

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

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

在面向对象的代码中

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

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

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

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

扩展名I

将代码添加到类的接口。

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

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

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

扩展II

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

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

扩展III

命名空间的基本功能是在某些代码中,如果使用关键字“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

你甚至可以将“污染”限制在一个班级:

#include <string>
#include <vector>

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

string ss ; // COMPILATION ERROR
vector vv ; // COMPILATION ERROR

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

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

因此,C ++名称空间有自己的语义。

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

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

结论

命名空间用于命名空间。 课程适用于班级。

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

当您需要名称空间时,请不要使用类。

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

答案 1 :(得分:51)

有很多人不同意我,但这就是我的看法:

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

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

例如,在您的情况下,问问自己,“什么是MyMath?”如果MyMath没有定义某种对象,那么会说:不要让它成为一个类。

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

答案 2 :(得分:15)

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

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


回应评论:是的,静态方法和静态数据往往被过度使用。这就是为什么我只提供两个相关的场景,我认为它们可以提供帮助。在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;

如果您不需要,无论如何使用命名空间。

答案 3 :(得分:11)

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

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

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

答案 4 :(得分:3)

我更喜欢命名空间,这样你就可以在实现文件中的匿名命名空间中拥有私有数据(因此它不必显示在标题中而不是private成员)。另一个好处是,通过using您的命名空间,方法的客户可以选择不指定MyMath::

答案 5 :(得分:1)

我想总结并添加到其他答案中。此外,我的观点是仅包含标题的世界。


命名空间

优点:

  • 命名层次结构的简单解决方案
  • 它们没有语义,所以阅读起来更简单
  • 可以存在于不同的文件(标题)中
  • 可以扩展
  • 日常学习
  • 可以定义快捷方式 (using)。
  • 可用于品牌推广(不过,您可以设计代码并为其添加命名空间)

缺点:

  • 一切都是公开的
  • 私有事物需要未命名的命名空间,因此它不是显式的
  • ADL(是的,有些人鄙视 ADL)
  • 可以扩展(这可能是件坏事,特别是结合 ADL,现有代码的语义可以通过扩展命名空间来改变)
  • 在运算符重载方面表现良好
  • 需要按照使用顺序定义(或声明)函数

具有静态方法的类

优点:

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

缺点:

  • 无 ADL
  • 无法扩展
  • 到处都需要关键字 static(有机会取笑该语言)
  • 单独解决命名问题是一种矫枉过正。在这种情况下难以阅读。
  • 函数(静态方法)总是需要限定(myclassspace::fun)。无法声明快捷方式 (using)。
  • 对于运算符重载几乎没用。
  • 不能用于品牌推广。
  • 你需要记住以 ; 结束:)

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

Bloomberg 等公司更喜欢类而不是命名空间。 如果您不喜欢 ADL 或运算符重载,则可以使用带有静态方法的类。

IMO,如果命名空间和类集成在一起成为同一枚硬币的两个方面,那就太好了。 例如,在默认情况下方法是静态的情况下,将语言中的命名空间标识为类。 然后就可以将它们用作模板参数。 我不确定如何处理 ADL(可能它可能仅限于符号运算符函数,例如 operatorX,这是运算符重载和 ADL 的最初动机)

答案 6 :(得分:0)

使用class的另一个原因 - 使用选项来使用访问说明符。然后,您可以将公共静态方法分解为较小的私有方法。公共方法可以调用多个私有方法。

答案 7 :(得分:0)

命名空间和类方法都有其用途。命名空间具有跨文件传播的能力,但如果您需要强制执行所有相关代码以进入一个文件,则这是一个弱点。如上所述,class还允许您在类中创建私有静态成员。您可以在实现文件的匿名命名空间中使用它,但它仍然比在类中使用它们更大的范围。