你如何 "declare" 全局结构?

How do you "declare" a global struct?

我有一个 .h 文件声明 3 different/similar class:

#ifndef _ICUSTOMCONTROLS_
#define _ICUSTOMCONTROLS_

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

public:
    // ..
};

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

public:
    // ..
};

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

public:
    // ..
};

#endif // !_ICUSTOMCONTROLS_

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

此时,在 CPP 中,我想对所有 3 个 classes 使用 common/global 结构 (IText)。如果我在 .h 中添加声明:

IText gTextCustomControl;

事实上它 "define" 它,所以我在编译时收到 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 中什么时候这将是 "processed"(也许以后是 classes 的 CTOR?也许更多次,浪费资源?)。我认为这不是一个好方法。

我也可以在 .h 上添加 extern 并按上面的方式定义它,但出于安全原因更糟(有人可以从 "extern" 访问它)。

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

如果您在 .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 在你需要的时候初始化,你可以把它的声明放在函数或某种单例中 class,例如:

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 的构造到首次使用,这可能不是您想要的。

"Bt I will never sure in the DLL when this will be "processed”(也许以后是类的CTOR?

这确实是正确的关注。 DLL 全局变量将从 DllMain 构建,并且 DllMain 受到 严重 的限制。您不能从那里加载其他 DLL(加载程序锁定),也不能执行任何会强制 Windows 加载其他 DLL 的操作。所以使用来自其他 DLL 的函数通常也被禁止(例外:如果你的 A.DLL 导致你的 B.DLL 被加载,那么 B.DLL 可能会调用来自 A.DLL 的函数。)。 =15=]

正确答案:

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

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