实现全局范围数据的最佳方式

时间:2010-03-20 17:20:07

标签: c++ scope global-variables global

我希望在C ++程序中制作程序范围的数据,而不会在所有源文件#include这个“全局变量存储库”文件时遇到麻烦的LNK2005错误。

我有两种方法可以用C ++来做,我问哪种方式更好

在C#中最简单的方法就是公共静态成员。

C#:

public static class DataContainer
{
    public static Object data1 ;
    public static Object data2 ;
}

在C ++中你可以做同样的事情

C ++全局数据方式#1:

class DataContainer
{
public:
    static Object data1 ;
    static Object data2 ;
} ;
Object DataContainer::data1 ;
Object DataContainer::data2 ;

然而,也有外部

C ++全局数据方式#2:

class DataContainer
{
public:
    Object data1 ;
    Object data2 ;
} ;
extern DataContainer * dataContainer ; // instantiate in .cpp file

在C ++ 中哪个更好,还是可能是我没想过的另一种方式?

解决方案必须不会导致LNK2005“对象已定义”错误。

6 个答案:

答案 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