更新一些旧代码并且原作者决定所有命令行参数变量都应该是全局变量。从测试和开发的角度来看,这显然使事情变得更具挑战性。
我的问题是如何最好地管理所有类需要使用的命令行参数(例如跟踪标志/调试标志)。同事建议至少将变量包装在命名空间中,但这似乎并不足够。我想过一个单身人士或静态课程,只是提供吸气剂,但这看起来并不优雅。另一方面,这似乎比必须将5个配置选项传递给每个需要知道调试和其他一些选项的类都要好。
答案 0 :(得分:4)
全局变量的最大问题是从函数中更改它们往往会成为引发错误的意外副作用。但是,在命令行参数的情况下,就运行进程而言,它们本质上是常量。阻止您声明它们const
的唯一方法是,在开始解析命令行时需要分配它们。
我建议创建一些机制,允许您在开头初始化参数,但随后阻止程序的任何部分更改它们。这将有效地避免全局变量通常会引入的任何缺点。
一种方法可能是ProgramArguments
类/结构,其中const成员通过解析命令行在构造函数中初始化。然后你可以有类似的东西:
std::unique_ptr<ProgramArguments const> g_program_arguments;
int main(int argc, char* argv[])
{
g_program_arguments.reset(new ProgramArguments(argc, argv));
if(g_program_arguments->verbose)
std::cout << "verbose!" << std::endl;
// ...
return 0;
}
这不会阻止您将指针更改为指向其他ProgramArguments实例。另一种方法可能是暂时抛弃constness以进行初始化:
struct ProgramArguments {
ProgramArguments() {}
bool verbose;
};
ProgramArguments const g_program_arguments;
void init_program_arguments(int argc, char* argv[])
{
ProgramArguments& program_arguments = const_cast<ProgramArguments&>(g_program_arguments);
program_arguments.verbose = true;
}
int main(int argc, char* argv[])
{
init_program_arguments(argc, argv);
if(g_program_arguments.verbose)
std::cout << "verbose!" << std::endl;
return 0;
}
答案 1 :(得分:0)
这取决于我们所谈论的全局数量。就个人而言,我认为在调试标志之类的内容中使用一些全局变量并说一个单独的日志管理器是可以的。
如果您真的想要遵守本书中的OOP原则,那么您必须将函数或对象所需的所有内容作为参数传递。从不访问全球状态。正如您所提到的,将许多常见参数传递给每个函数都会很快变得无聊,因此可以帮助您缓解这一问题的一种模式是Context Object。