在 C 中哪里声明/定义类作用域常量?

发布于 2024-08-17 20:09:19 字数 844 浏览 4 评论 0原文

我很好奇 C++ 中不同常量声明和定义选项的优点/缺点。在最长的时间里,我只是在类定义之前的头文件顶部声明它们:

//.h
const int MyConst = 10;
const string MyStrConst = "String";
class MyClass {
...
};

虽然这会污染全局名称空间(我知道这是一件坏事,但从未找到原因的详细清单)是坏的),常量仍将作用于各个翻译单元,因此不包含此标头的文件将无法访问这些常量。但是,如果其他类定义了同名的常量,则可能会发生名称冲突,这可以说不是一件坏事,因为它可能很好地表明了可以重构的区域。

最近,我决定最好在类定义本身内部声明类特定常量:

//.h
class MyClass {
    public:
         static const int MyConst = 10;
...
    private:
         static const string MyStrConst;
...
};
//.cpp
const string MyClass::MyStrConst = "String";

常量的可见性将根据该常量是仅在类内部使用还是其他使用该常量的对象需要进行调整。班级。我认为这是目前最好的选择,主要是因为您可以将内部类常量保留为该类的私有,并且使用公共常量的任何其他类都会对常量的源有更详细的引用(例如 MyClass: :我的Const)。它也不会污染全局名称空间。尽管它确实有需要在 cpp 文件中进行非完整初始化的缺点。

我还考虑过将常量移动到它们自己的头文件中,并将它们包装在命名空间中,以防其他类需要常量,但不需要整个类定义。

只是寻找意见和可能的其他我还没有考虑过的选择。

I'm curious about the benefits/detriments of different constant declaration and definition options in C++. For the longest time, I've just been declaring them at the top of the header file before the class definition:

//.h
const int MyConst = 10;
const string MyStrConst = "String";
class MyClass {
...
};

While this pollutes the global namespace (which I know is a bad thing, but have never found a laundry list of reasons why it is bad), the constants will still be scoped to individual translation units, so files that don't include this header won't have access to these constants. But you can get name collisions if other classes define a constant of the same name, which is arguably not a bad thing as it may be a good indication of an area that could be refactored.

Recently, I decided that it would be better to declare class specific constants inside of the class definition itself:

//.h
class MyClass {
    public:
         static const int MyConst = 10;
...
    private:
         static const string MyStrConst;
...
};
//.cpp
const string MyClass::MyStrConst = "String";

The visibility of the constant would be adjusted depending on whether the constant is used only internally to the class or is needed for other objects that use the class. This is what I'm thinking is the best option right now, mainly because you can keep internal class constants private to the class and any other classes using the public constants would have a more detailed reference to the source of the constant (e.g. MyClass::MyConst). It also won't pollute the global namespace. Though it does have the detriment of requiring non-integral initialization in the cpp file.

I've also considered moving the constants into their own header file and wrapping them in a namespace in case some other class needs the constants, but not the whole class definition.

Just looking for opinions and possibly other options I hadn't considered yet.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

红尘作伴 2024-08-24 20:09:19

可以这么说,您声称将非整数常量声明为静态类成员“会损害在 cpp 文件中要求非整数初始化”并不完全可靠。它确实需要在 cpp 文件中定义,但这不是“损害”,而是您的意图问题。 C++ 中的命名空间级 const 对象默认具有内部链接,这意味着在原始变体中,声明

const string MyStrConst = "String"; 

等效于

static const string MyStrConst = "String"; 

,即它将在每个翻译单元中定义一个独立的 MyStrConst 对象该头文件包含在其中。你知道这一点吗?这是你的意图还是无意的?

无论如何,如果您不需要在每个翻译单元中特别有一个单独的对象,那么在原始示例中声明MyStrConst常量并不是一个好的做法。通常,您只需在头文件中放置非定义声明

extern const string MyStrConst; 

,并在 cpp 文件中提供定义,

const string MyStrConst = "String";

从而确保整个程序使用相同的常量对象。换句话说,当涉及到非整数常量时,通常的做法是在cpp文件中定义它们。因此,无论您如何声明它(在类中或类外),您通常总是必须处理必须在 cpp 文件中定义它的“损害”。当然,正如我上面所说,使用名称空间常量,您可以摆脱第一个变体中的内容,但这只是“惰性编码”的一个示例。

无论如何,我认为没有理由使问题过于复杂:如果常量对类有明显的“依附”,则应将其声明为类成员。

PS 访问说明符(publicprotectedprivate)不控制名称的可见性。他们仅控制其可访问性。无论如何,该名称仍然可见。

Your claim that declaring a non-integral constant as a static class member "have the detriment of requiring non-integral initialization in the cpp file" is not exactly solid, so to say. It does require a definition in cpp file, but it is not a "detriment", it is a matter of your intent. Namespace-level const object in C++ has internal linkage by default, meaning that in your original variant the declaration

const string MyStrConst = "String"; 

is equivalent to

static const string MyStrConst = "String"; 

i.e. it will define an independent MyStrConst object in every translation unit into which this header file is included. Are you aware of this? Was this your intent or not?

In any case, if you don't specifically need a separate object in every translation unit, the declaration of MyStrConst constant in your original example is not a good practice. Normally, you'd only put a non-defining declaration in the header file

extern const string MyStrConst; 

and provide a definition in the cpp file

const string MyStrConst = "String";

thus making sure that the entire program uses the same constant object. In other words, when it comes to non-integral constants, a normal practice is to define them in cpp file. So, regardless of how you declare it (in the class or out) you will normally always have to deal with the "detriment" of having to define it in cpp file. Of course, as I said above, with namespace constants you can get away with what you have in your first variant, but that would be just an example of "lazy coding".

Anyway, I don't think there is a reason to over-complicate the issue: if the constant has an obvious "attachment" to the class, it should be declared as a class member.

P.S. Access specifiers (public, protected, private) don't control visibility of the name. They only control its accessibility. The name remains visible in any case.

安静 2024-08-24 20:09:19

全局名称空间的污染很糟糕,因为有人(例如您使用的库的编写者)可能想将名称 MyConst 用于其他目的。这可能会导致严重的问题(不能一起使用的库等)

。如果常量链接到单个类,您的第二个解决方案显然是最好的。如果这不是那么容易(考虑与程序中的类无关的物理或数学常量),则命名空间解决方案比这更好。顺便说一句:如果您必须兼容较旧的 C++ 编译器,请记住其中一些编译器不能在头文件中使用整体初始化 - 在这种情况下您必须在 C++ 文件中初始化或使用旧的 enum 技巧。

我认为对于常量没有更好的选择 - 至少目前想不到......

Pollution of the global namespace is bad because someone (e.g. the writer of a library you use) might want to use the name MyConst for another purpose. This can lead to severe problems (libraries that can't be used together etc.)

Your second solution is clearly the best if the constants are linked to a single class. If that isn't so easy (think of physical or math constants without ties to a class in your program), the namespace solution is better than that. BTW: if you must be compatible to older C++ compilers, remember some of them can't use integral initialization in a header file - you must initialize in the C++ file or use the old enum trick in this case.

I think there are no better options for constants - at least can't think of one at the moment...

扮仙女 2024-08-24 20:09:19

污染全局命名空间应该是不言而喻的坏事。如果我包含头文件,我不想遇到或调试与该头文件中声明的常量的名称冲突。这些类型的错误确实令人沮丧,有时很难诊断。例如,我曾经不得不链接到一个在标头中定义了以下内容的项目:

#define read _read

如果您的常量是命名空间污染,那么这就是命名空间核废物。其表现是一系列非常奇怪的编译器错误,抱怨缺少 _read 函数,但仅限于链接该库时。我们最终将读取函数重命名为其他函数,这并不困难,但应该是不必要的。

您的第二个解决方案非常合理,因为它将变量放入范围内。没有理由这必须与类相关联,如果我需要在类之间共享常量,我将在它们自己的命名空间和头文件中声明常量。这对于编译时来说并不是很好,但有时是必要的。

我还看到人们将常量放入自己的类中,这些常量可以作为单例实现。对我来说,这似乎是没有回报的工作,该语言为您提供了一些声明常量的设施。

Polluting the global namespace should be self-evidently bad. If I include a header file, I don't want to encounter or debug name collisions with constants declared in that header. These types of errors are really frustrating and sometimes hard to diagnose. For example, I once had to link against a project that had this defined in a header:

#define read _read

If your constants are namespace pollution, this is namespace nuclear waste. The manifestation of this was a a series of very odd compiler errors complaining about missing the _read function, but only when linking against that library. We eventually renamed the read functions to something else, which isn't difficult but should be unnecessary.

Your second solution is very reasonable as it puts the variable into scope. There's no reason that this has to be associated with a class, and if I need to share constants among classes I'll declare constants in their own namespace and header file. This isn't great for compile-time, but sometimes it's necessary.

I've also seen people put constants into their own class, which can be implemented as a singleton. This to me seems work without reward, the language provides you some facilities for declaring constants.

铃予 2024-08-24 20:09:19

您可以在 c++ 文件中将它们声明为全局变量,只要它们不在标头中引用即可。那么它们对于该类来说是私有的,并且不会污染全局名称空间。

You can declare them as globals in the c++ file, as long as they are not referenced in the header. Then they are private to that class and won't pollute the global namespace.

我要还你自由 2024-08-24 20:09:19

我个人使用你的第二种方法;我已经使用它很多年了,它对我来说效果很好。

从可见性的角度来看,我倾向于将私有常量设置为文件级静态,因为实现文件之外的任何人都不需要知道它们的存在;如果您需要更改它们的名称或添加新名称,因为它们的名称范围与其使用范围相同,这有助于防止链式反应重新编译...

Personally I use your second approach; I've used it for years, and it works well for me.

From a visibility point I would tend to make the private constants file level statics as nobody outside the implementation file needs to know they exist; this helps prevent chain reaction recompiles if you need to change their names or add new ones as their name scope is the same as their usage scope...

溺渁∝ 2024-08-24 20:09:19

如果只有一个类要使用这些常量,请在类体内将它们声明为static const。如果一堆相关的类要使用常量,请在仅保存常量和实用方法的类/结构内或在专用命名空间内声明它们。例如,

namespace MyAppAudioConstants
{
     //declare constants here
}

如果它们是整个应用程序(或其大部分)使用的常量,请在各处(隐式或显式)包含的标头的命名空间内声明它们。

namespace MyAppGlobalConstants
{
    //declare constants here
}

If only one class is going to use these constants, declare them as static const inside the class body. If a bunch of related classes are going to use the constants, declare them either inside a class/struct that only holds the constants and utility methods or inside a dedicated namespace. For example,

namespace MyAppAudioConstants
{
     //declare constants here
}

If they are constants used by the whole application (or substantial chunks of it), declare them inside a namespace in a header that is (either implicitly or explicitly) included everywhere.

namespace MyAppGlobalConstants
{
    //declare constants here
}
平定天下 2024-08-24 20:09:19

不要污染全局名称空间,污染本地名称空间。

namespace Space
  {
  const int Pint;
  class Class {};
  };

但实际上...

class Class
  {
  static int Bar() {return 357;}
  };

don't pollute global namespace, pollute local.

namespace Space
  {
  const int Pint;
  class Class {};
  };

But practically...

class Class
  {
  static int Bar() {return 357;}
  };
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文