如何避免全局变量和幻数?

时间:2010-09-09 22:54:20

标签: c++ c global-variables magic-numbers

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

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

doSomethingWithValue(1920);

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

const int SCREEN_WIDTH = 1920;

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

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

10 个答案:

答案 0 :(得分:11)

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

在C中,如果它是一个整数常量,你可能想要使用枚举,因为const对象不是常量。在C ++中,首选使用与原始问题类似的const对象,因为在C ++中,const对象是常量。

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

答案 1 :(得分:5)

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

答案 2 :(得分:2)

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

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

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

另一个重点是 immutable 全局数据通常没有任何问题。

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

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

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

答案 3 :(得分:1)

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

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

答案 4 :(得分:1)

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

答案 5 :(得分:1)

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

无论如何,如果你不喜欢这样的“浮动”常量,你可以把它放在一个命名空间或者其他什么来收集那个类型的所有常量。在某些情况下,您还可以考虑枚举枚举相关常量。

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

答案 6 :(得分:1)

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

另一篇可能help

的帖子

答案 7 :(得分:1)

虽然你的第二个案例中的全局是一个相当无害的,但除非你设计的是你确定的东西,否则屏幕宽度不会改变,我会用一些东西来动态获取屏幕宽度(例如,在Windows上为GetSystemMetrics,或在X上为XDisplayWidth

答案 8 :(得分:1)

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

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

您的计划扩展的额外功能:

  • 当你有一天你的程序可以自定义时,你可以让它在构造函数中设置属性,而不是重新编译所有东西。
  • 当您想要在同一个过程中将两个程序实例彼此相邻时,它们可以有不同的设置。
但是,对于一个快速的一次性计划来说,这不是一个大问题。

答案 9 :(得分:0)

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

不可能处理所有可能的意外事故,人们不应该过于努力地防范那些根本不会发生的事情。尽管如此,人们应该注意事情会发生什么变化,以免自己陷入困境。

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

相关问题