2012-12-15 43 views
0

我觉得这个问题可能有一个简单的解决方案,这对我来说并不明显 - 我有一个配置类,用于存储从ini文件加载的各种配置选项等。在我的应用程序中,我有一个库和客户端,以及2个配置 - 将库构建为DLL并使客户端动态链接,或将它们作为单个二进制构建在一起。那么如何在库和客户端中使用/使用我的配置对象呢?如果我在两者中都包含配置类定义,我认为它会因重新定义而给我提供链接错误。如何设计一个配置工具既可以静态链接也可以动态链接?

回答

0

如果我在两者中都包含配置类定义,我认为它会因重新定义而给我提供链接错误。

不,它不会。 Windows DLL不尊重一个定义规则。基本上,在Windows中,ODR在模块边界处停止,即ODR在内可执行,而内但不在它们之间。这是不是一件好事是不相关的,就是这样。所以,你可以在DLL和可执行文件中包含你的配置类的定义。但是,将会有两个独立的单例实例(因为我认为它是单例类,正如配置类通常那样),每个模块都有一个实例。从这个意义上讲,它不会是一个真正的单身人士,至少,不是跨模块。

如果你想要一个真正的模块单身人士,你将不得不做更多的工作。您有两种选择:主从或合并(或“菊花链”)。

第一个选项是指定一个模块(例如,可执行文件)作为实例化(并保留)单例对象的模块,然后将指向该实例的指针传递给所有“从”模块,然后通过一个通用接口使用它(因此两个模块对于配置类都有相同的声明,但只有一个模块创建它并将其传递给其他模块)。这将是这个样子:

在头文件 “config_class.h”:

class ConfigClass { 

    // a bunch of declarations... 

    public: 
    static ConfigClass& getInstance(); // the access-point for the singleton. 
}; 

#ifdef MY_LIB_NOW_BUILDING_MASTER 

extern "C" __declspec(dllimport) void setConfigClassInstance(ConfigClass* pobj); 

#else 

extern "C" __declspec(dllexport) void setConfigClassInstance(ConfigClass* pobj); 

#endif 

在cpp文件 “config_class.cpp”:

#include "config_class.h" 

// a bunch of definitions for the config_class member functions. 

#ifdef MY_LIB_NOW_BUILDING_MASTER 

ConfigClass& ConfigClass::getInstance() { 
    static ConfigClass instance(/* */); 
    return instance; 
}; 

#else 

static ConfigClass* masterInstance; 

void setConfigClassInstance(ConfigClass* pobj) { 
    masterInstance = pobj; 
}; 

ConfigClass& ConfigClass::getInstance() { 
    return *masterInstance; 
}; 

#endif 

,其中,在上述例如,您可以从主模块(很可能是主可执行文件)中调用setConfigClassInstance来为DLL设置配置对象,但要确保DLL在静态初始化(加载)期间不需要配置类。

第二个选择是合并或菊花链你的单身人士。在这种情况下,每个模块创建自己的单例实例,然后使用与上面类似的方案,将指针传递给彼此的实例,从而将它们合并为一个实例(交叉链接),或者将它们链接在一起(例如,像循环链表或环形列表),并将呼叫分派给相应的实例。

我认为对于您的应用程序,第一个选项可能是最简单的。

N.B .:在非Windows环境下,情况完全不同,以上都不适用。

+0

“如果我在两者中都包含配置类定义,我认为它会因重新定义而给我提供链接错误。”语句是用于静态链接(将dll构建为a。lib),而不是动态的;我相信你用上面提供的解决方案,同样会发生。我相信我可以通过预处理器定义的丰富多彩的使用来解决这个问题,但是如果可能的话,我试图避免使用特定的方法。 – Rollie

+0

@Rollie哦,所以,如果我得到这个权利,让我们说你有:main.cpp(应用程序代码),lib.cpp(库代码)和config.cpp(配置类代码)。其中编译成main.o,lib.o和config.o。然后你建立一个“exe + dll”为“(main.o,config.o)+(lib.o,config.o)”的版本,然后你想把dll变成一个静态库,并且天真地尝试链接(main.o,config.o,lib.o,config.o)并获得ODR错误。解决方案很简单,只是在构建静态版本时不要多次链接配置代码。而已。 –