在一个类中定义常量与在命名空间中定义有什么区别?

3

可能是重复问题:
静态成员类与普通的C样式接口

我正在查看某人的代码,有几十个常量在一个类中定义如下:

// header file

class Defines
{
public:
    static const int Val1;
    static const int ValN;
    static const char* String1;
    static const char* StringN;
...
}

// .CPP
const char* Defines::String1 = "some value"
etc.

与使用命名空间相比,这样做的原因是什么?它们之间有优缺点吗?

--------- 编辑 ----------

很抱歉,我显然应该明确指出这一点,因为没有人从类的名称 - "Defines"中推断出来 - 即这些常量与特定类无关,已经创建了一个专门用于保存常量而不包含其他内容的类 Defines。

我的问题不是为什么要将常量放置在特定的类中,而是有没有价值将它们收集在一起并放置在一个只收集常量的类中,而不是将它们收集在命名空间中,或者仅将它们收集在专门用于此目的的头文件中等。

(项目中没有当前存在的命名空间,因此答案中提到的污染命名空间的潜在问题在这种情况下不相关。)

----- 第32次编辑 -----------

另外一个问题是 --- 将

const char* Defines::StringN = "Somevalue"

放在.h文件中与放在.cpp文件中相比效率低吗?

5个回答

2

因为这些常量可能与该类紧密耦合。例如,类的成员可能将这些常量作为参数或返回值。也许它们只有在与该类的接口相关时才有意义,因此将它们放在单独的命名空间中是没有意义的,因为它们只与该类相关。


2
这里没有理由按照这种方式进行操作,就像没有真正的理由使用class Defines { public: ... };而非struct Defines { ... };。或许编写代码的人之前在使用不支持命名空间/命名空间中全局变量的语言编写代码, 或者认为这样看起来比很多extern语句和命名空间更加整洁。
然而,如果您打算将其中一些常量设为私有,并仅向少数函数/类提供访问权限,则有一些实际用途。但从现在的情况来看,似乎并非如此,将其改为命名空间可能更加合理——这样,可以使用using Defines::constant;等。
对第一次修改的回应:全局命名空间也是一个命名空间,而且它比其他命名空间更容易混淆,因为东西更容易泄漏到其中。在这种意义上,将变量放在类中会更好,但仍不如将它们放在自己的命名空间中。
对第二次修改的回应:在头文件中使用const char* Defines::StringN = "Somevalue";会导致该常量被多次定义,程序将无法链接。然而,如果在其前面添加一个extern并将定义放在.cpp文件中,一切都会很好,不会有性能惩罚。

1

有几个原因:

  1. 您没有将潜在的随机常量弄乱您的命名空间。
  2. 通过将它们与其关联的类一起包含,您为类和常量本身添加了含义。

如果我定义了一个名为 NAME 的全局/命名空间常量,那么它与什么相关?如果将其添加到类本身中,则必须使用类名引用它,这增加了使用的含义,使代码更易读且更少出错。

当然,这可能会被滥用。您可以放错常量,也可以在特定的类中不适当地放置真正的全局常量。在这两种情况下,都可能给常量命名不当。


然而,1)没有先前存在的名称空间来混淆。2)正如类“Defines”的名称所示,它们属于自己的类别,与它们相关的特定类别无关。 - Gruntcakes
它仍然具有意义,因为您知道它来自哪里(因此,如果需要,可以查找它的位置),并且它集中了分发,而不是使一堆命名空间全局变量存在于随机文件中。它集中了位置,类似于将本地化细节存储到单个资源文件中(至少对于给定的单元)。 - pickypg
抱歉,我不明白将常量收集到类中与将它们收集到命名空间中有什么区别。命名空间同样集中了它们的分发,并且您知道在哪里查找它们,那么为什么使用类比使用命名空间更好呢?我的问题不是为什么要将它们收集在一起,而是是否要将它们收集到类或命名空间中,如果是类,为什么选择类而不是命名空间,如果是命名空间,为什么选择命名空间而不是类,如果没有区别,那也是一个答案。 - Gruntcakes
这主要是一种设计方法。坦白地说,很多都取决于个人偏好和经验。 - pickypg

0
对于大多数事情来说,把它们的作用范围限制在最小范围内是很有道理的。在这种情况下,并不是可见性的问题,而是为了使代码更加清晰明了。
如果你在一个方法中看到`String1`,你根本不知道它是从哪里来的。但是,如果你看到`Defines::String1`,你就可以说:“好吧,这是一个来自类`Defines`的变量,让我去那里看看它是什么,应该是什么。”只需要查看一个类要比查看可能分布在多个源文件中的整个命名空间好得多。显然,如果变量存在于某个类中,因为它主要在该类中使用,那么毫无疑问,它应该在那里。:D

0
一般来说,没有理由这样使用类型。有人认为,如果“常量集合”演变成具体对象,从这个方式开始会使过渡更容易。实际上,我从未见过这种情况发生。它只是隐藏了意图,并可能用私有构造函数使代码混乱。
有人可以认为类与模板一起工作,而命名空间则不行。因此,只有在Defines是一个类的情况下,以下内容才能正常工作:
template<typename T> int function() {
    return T::x + T::y;
}
//later
cout << function<Defines>() << function<OtherDefines>() << endl;

在大多数情况下,可能有一个更好的重新设计方案,特别是如果你只有一些并非真正意义上的“常量”。尽管偶尔会有用处。
有时,它也可以对抗参数相关查找。简而言之,编译器允许根据传递给函数的参数扩展其对不同名称命名空间中合格函数名称的搜索。这不适用于类的静态函数。然而,这更适用于一般情况,其中“静态类”还包括嵌套类型和函数以及常量集合。
为什么人们这样做各有不同。有些人来自不能以这种方式使用的语言,而其他人则只是不知道更好的方法。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接