1

我知道并理解全局变量和幻数是编程时要避免的事情,尤其是随着项目中代码量的增加。但是,我想不出避免两者的好方法。

假设我有一个预先确定的表示屏幕宽度的变量,并且在多个文件中需要该值。我可以...

doSomethingWithValue(1920);

但这是一个神奇的数字。但为了避免这种情况,我会做...

const int SCREEN_WIDTH = 1920;

//In a later file...
extern const int SCREEN_WIDTH;
doSomethingWithValue(SCREEN_WIDTH);

现在我正在使用一个全局变量。这里有什么解决方案?

4

10 回答 10

11

在您的第二个示例中,SCREEN_WIDTH它实际上不是一个变量1,而是一个命名常量。使用命名常量没有任何问题。

在 C 中,如果它是整数常量,您可能希望使用枚举,因为 const 对象不是常量。在 C++ 中,最好使用原始问题中的 const 对象,因为在 C++ 中,const 对象是一个常量。

1. 从技术上讲,是的,它是一个“变量”,但这个名称并不真正“正确”,因为它永远不会改变。

于 2010-09-09T22:55:24.257 回答
5

我建议在头文件的命名空间中定义常量。然后范围不是全局的,您不需要在多个地方重新定义它(即使使用 extern 关键字)。

于 2010-09-09T23:00:07.087 回答
2

为什么首先需要硬编码屏幕宽度?它从何而来?在大多数实际应用程序中,它来自一些系统 API,它告诉您当前正在运行哪种分辨率,或者系统能够显示哪些分辨率。

然后,您只需获取该值并将其传递到需要的任何地方。

简而言之,在这条线上:doSomethingWithValue(SCREEN_WIDTH); 你已经在这样做了。SCREEN_WIDTH在这个特定的示例中可能是全局的,但它不一定是,因为该函数没有将它作为全局访问。您在运行时将值传递给函数,因此函数看到的不是全局变量,它只是一个普通的函数参数。

另一个重要的一点是,不可变的全局数据通常没有任何问题。

全局常量通常很好。当您具有可变的全局状态时会出现问题:可以在整个应用程序中访问的对象,并且可能具有不同的值,具体取决于您查看的时间。这使得它难以推理,并导致许多问题。

但是全局常量是安全的。以 pi 为例。它是一个数学常数,让每个函数都看到 pi 是 3.1415 并没有什么坏处……因为它就是这样,而且它不会改变。

如果屏幕宽度是硬编码的常量(如您的示例中),那么它也可以是全局的而不会造成破坏。(尽管出于显而易见的原因,它可能一开始就不应该是一个常数9

于 2010-09-09T22:57:59.280 回答
1

全局变量的主要问题是当它们是非常量时。不变的全局变量几乎不是一个问题,因为您在任何使用它们的地方总是知道它们的价值。

在这种情况下,一种明智的方法是创建一个常量命名空间并将常量值放在那里,以供程序中的任何位置引用。这很像你的第二个例子。

于 2010-09-09T22:56:57.193 回答
1

它们必须在某个地方定义。为什么不将定义放在 .h 文件或构建文件中?

于 2010-09-09T22:57:29.433 回答
1

它不是变量,它是常量,在编译时被解析。

无论如何,如果您不喜欢这样的“浮动”常量,您可以将它放在命名空间或其他任何东西中以将所有该类型的常量收集在一起。在某些情况下,您还可以考虑使用枚举来对相关常量进行分组。

更好的是,如果这适用于您的情况,请避免使用固定的预定屏幕宽度并使用正确的 API 在运行时检索它。

于 2010-09-09T22:58:13.150 回答
1

如果全局是必须的,那么将它包装在一个函数中并使用该函数来获取值通常是一个好主意。

另一个可能有帮助的帖子

于 2010-09-09T22:58:38.030 回答
1

虽然第二种情况下的全局是一个相当无害的,除非你正在设计这个你确定屏幕宽度不会改变的东西,我会使用一些东西来动态获取屏幕宽度(例如,GetSystemMetrics在 Windows ,或XDisplayWidth在 X 上)。

于 2010-09-09T23:04:03.670 回答
1

避免这种情况的一种方法是将程序设置为对象并在对象上具有属性(my_prog.screen_width)。要运行您的程序,请让 main() 实例化对象并在对象上调用 ->go 方法。

Java 就是这样做的。很多。半体面的想法。

程序扩展的奖励功能:

  • 当你有一天让你的程序可定制时,你可以让它在构造函数中设置属性,而不是重新编译所有东西。
  • 当您想在同一进程中运行程序的两个实例时,它们可以有不同的设置。

不过,对于一个快速的一次性程序来说,这并不是什么大不了的事。

于 2010-09-09T23:16:43.083 回答
0

重要的是要认识到,如果将来需要更改全局常量,有时也会导致问题。在某些情况下,您可能会决定根本不让他们改变,但其他时候事情可能并不那么容易。例如,您的程序可能包含大小与屏幕匹配的图形图像;如果需要调整它以在不同尺寸的屏幕上运行会发生什么?仅仅改变命名常量不一定能修复程序中嵌入的图形图像。如果它需要能够在运行时决定使用什么尺寸的屏幕怎么办?

不可能处理所有可以想象的意外事件,人们不应该过分努力地防止那些根本不会发生的事情。尽管如此,人们应该注意事情会发生什么变化,以免将自己逼入绝境。

在设计一个类时,拥有一个返回不变值的虚拟只读属性将允许该类的未来扩展返回不同的值。使用属性而不是常量可能会对性能产生一些影响,但在某些情况下,灵活性是值得的。如果有一种方法来定义虚拟常量可能会很好,而且我认为 .net 理论上没有理由允许它(包括带有虚拟方法指针的表中的常量值),但就目前而言我知道它没有。

于 2010-09-09T23:44:57.007 回答