我希望在C ++程序中制作程序范围的数据,而不会在所有源文件#include这个“全局变量存储库”文件时遇到麻烦的LNK2005错误。
我有两种方法可以用C ++来做,我问哪种方式更好。
在C#中最简单的方法就是公共静态成员。
C#:
public static class DataContainer
{
public static Object data1 ;
public static Object data2 ;
}
在C ++中你可以做同样的事情
class DataContainer
{
public:
static Object data1 ;
static Object data2 ;
} ;
Object DataContainer::data1 ;
Object DataContainer::data2 ;
然而,也有外部
class DataContainer
{
public:
Object data1 ;
Object data2 ;
} ;
extern DataContainer * dataContainer ; // instantiate in .cpp file
在C ++ 中哪个更好,还是可能是我没想过的另一种方式?
解决方案必须不会导致LNK2005“对象已定义”错误。
答案 0 :(得分:12)
如果您必须拥有一些全局对象,那么最简单的方法就是在头文件中声明它们extern
,这些头文件包含在需要访问它们的任何地方,并在单个源文件中定义它们。
您的方式#1使用仅包含static
成员的类,这意味着它实际上是在完成命名空间的工作,为什么不使用命名空间呢?
方式#2聚合一个类中的两个对象,但如果两个对象之间没有真正的相互依赖性,则没有特别的好处。
我建议将对象放在namespace
中,以防止污染全局命名空间,并使用data1
等潜在的常用标识符,
// File: globaldata.h
#ifndef GLOBALDATA_H
#define GLOBALDATA_H
#include "Object.h" // Definition of Object might be here
namespace GlobalData
{
extern Object data1;
extern Obejct data2;
}
#endif GLOBALDATA_H
// File: globaldata.cc
#include globaldata.h
namespace GlobalData
{
Object data1;
Object data2;
}
然后你可以在其他地方访问它们。
#include "globaldata.h"
// Does something with global data
void f()
{
GlobalData::data1.doSomething();
}
答案 1 :(得分:8)
更好的方法是将对象放在命名空间中。
// header
namespace global // or any appropriate name
{
extern Object data1 ;
extern Object data2 ;
}
// cpp
namespace global // or any appropriate name
{
Object data1 ;
Object data2 ;
}
正如在commments中预先准备的那样:为了做到这一点,不要忘记使用extern
限定符来声明(在头文件中)以指定每个对象中只有一个实例(在cpp文件中)
答案 2 :(得分:3)
公共静态变量只是全局变量,而全局变量很糟糕。如果一个对象依赖于你想要创建全局的一些数据,那么为这个依赖项创建一个setter,并拥有某种“工厂”类,它将你的应用程序从小而独立的部分组合在一起,通过setter提供全局依赖。像这样,在伪代码中:
class A:
has dependency1 of type X;
has dependency2 of type Y;
class Factory:
has sharedX of type X;
has sharedY of type Y;
init:
sharedX = createX;
sharedY = createY;
wireApplication:
instanceOfA = createA;
instanceOfA.setDependency1(sharedX);
instanceOfA.setDependency2(sharedY);
return instanceOfA;
这样,通过访问静态变量,A的依赖关系不会被硬编码。这有几个好处。首先,它们更加明显,因为您不会秘密从实现文件中的其他类中提取信息。其次,它们不是一成不变的,因为你实际上可以创建A而不用它来拉X和Y.第三,你可以精确控制X和Y的寿命。
请参阅MiškoHevery关于单身人士的优秀博客文章系列 - 您可以从Singletons are Pathological Liars开始,然后按照其中的链接进行操作。
答案 3 :(得分:2)
LNK2005
”)与链接有关,而不是源语言级别范围。 C#混淆了这些东西(虽然我认为这不一定是件坏事)比C ++更复杂(但C ++也在某种程度上这样做,例如extern
关键字)。没有解决这个问题的方法将完全存在于编译器和预处理器领域。链接器以及如何构建程序将发挥作用。
您的两个解决方案实际上都使用extern
(外部链接)来解决问题,它只是隐含在第一种情况下。实际上,“程序范围”的数据非常模糊。你的意思是“过程广泛”吗?或者在程序的所有实例中共享?基于错误消息,我假设您正在处理Windows。你的程序是否有/使用DLL?这个“程序范围”的数据是否需要或应该在不同的dll之间共享?
答案 4 :(得分:1)
在头文件中(我将其称为Data.h):
namespace Data
{
extern Object data1;
extern Object data2;
}
在任何需要了解它的源文件中:
#include "Data.h"
对于Data.cpp,您可以编写
#include "Data.h"
Object Data::data1;
Object Data::data1;
或
#include "Data.h"
namespace Data
{
Object data1;
Object data2;
}
答案 5 :(得分:1)
KISS。
DataContainer.h
#pragma once
namespace DataContainer {
extern Object data1;
extern Object data2;
} // namespace DataContainer
DataContainer.cpp
#include <DataContainer.h>
namespace DataContainer {
Object data1;
Object data2;
}// namespace DataContainer