你如何宣布"全局结构?

时间:2016-08-05 08:00:06

标签: c++ struct global

我是一个声明3个不同/相似类的.h文件:

#ifndef _ICUSTOMCONTROLS_
#define _ICUSTOMCONTROLS_

class ICustomKnob1 : public IKnobControl
{
private:
    // ..

public:
    // ..
};

class ICustomKnob2 : public IControl
{
private:
    // ..

public:
    // ..
};

class ICustomButton : public IButtonControl
{
private:
    // ..

public:
    // ..
};

#endif // !_ICUSTOMCONTROLS_

我是一个定义这些类的cpp文件。我将.h包含在cpp中,也包含在项目中的其他.h / .cpp文件中(这是一个DLL)。

此时,在CPP中,我想对所有3个类使用公共/全局结构(IText)。如果我在.h中添加声明:

IText gTextCustomControl;

实际上它"定义"它,所以我在编译时遇到了LNK1169 one or more multiply defined symbols found错误消息(正如我所说,我多次添加.h。)

我可以在.cpp文件中添加它(带有真正的定义):

IText gTextCustomControl = IText(12, &COLOR_WHITE, "Arial", IText::kStyleBold, IText::kAlignCenter, 0, IText::kQualityDefault);

但我永远不会在DLL中确定这将是"处理" (可能是以后的课程的CTOR?可能更多次,浪费资源?)。我认为这不是一个好方法。

我也可以在.h上添加extern并将其定义如上,但出于安全原因更糟糕(有人可以从" extern"访问它)。

你会如何处理这种情况?或者它不可能跨对象共享一个共同的结构?

2 个答案:

答案 0 :(得分:3)

“Bt我永远不会在DLL中确定这将被”处理“(可能是以后的类的CTOR?”

这确实是正确的问题。 DLL全局变量将由DllMain构建,而DllMain 严重 受限于它可以执行的操作。你不能从那里加载其他DLL(加载器锁),或做任何会迫使Windows加载其他DLL的东西。因此,通常也禁止使用来自其他DLL的函数(例外:如果您的A.DLL导致加载B.DLL,那么B.DLL可以从A.DLL调用函数。)。

正确的解决方案:

IText& getTextCustomControl();
...
IText& getTextCustomControl() {
   static IText retval (12, &COLOR_WHITE, "Arial", IText::kStyleBold,
                 IText::kAlignCenter, 0, IText::kQualityDefault);
   return retval;
}

这会在第一次调用getTextCustomControl时初始化对象,这通常会在所有DllMain()函数完成后发生。

答案 1 :(得分:1)

如果在.cpp中创建全局变量,则无法保证在其他全局变量之前对其进行初始化(参见§3.6.3/ 2 [basic.start.dynamic] ),特别是:

// dll.cpp

IText gTextCustomControl = ...;

ICustomKnob2::ICustomKnob2 () {
    gTextCustomControl.doSomething();
}

// main.cpp

ICustomKnob2 knob2; // Oops! gTextCustomControl may be initialized after this.

如果你想确保gTextCustomControl在需要时初始化,你可以把它的声明放在一个函数或某种单例类中,例如:

IText& get_gTextCustomControl () {
   static IText ins(12, &COLOR_WHITE, "Arial", IText::kStyleBold, 
                    IText::kAlignCenter, 0, IText::kQualityDefault);
   return ins;
}

然后使用它而不是全局变量,这将确保在使用它之前构造实例。

ICustomKnob2::ICustomKnob2 () {
    get_gTextCustomControl().doSomething();
}

显然,这会将gTextCustomControl的构建推迟到第一次使用,这可能不是你想要的。