我是一个声明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"访问它)。
你会如何处理这种情况?或者它不可能跨对象共享一个共同的结构?
答案 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
的构建推迟到第一次使用,这可能不是你想要的。