摘要:
目的:见标题
问题复现:
利用具体类型将C++模板类实例化出单例,然后用不同的类A和B来继承,并导出这俩类让别的dll使用,发现通过A和B得到的单例是同一个单例(内存地址都一样)。
module1.dll里,用Dll.h导出:
#if defined (__KERNEL_BUILD__)
#define HCHXKernel_EXPORT EXPORT_ATTRIBUTE
#else
#define HCHXKernel_EXPORT IMPORT_ATTRIBUTE
#endif
//类型
struct Kernel_EXPORT ObjectType
{
int mMainType;/*主类型,比如:井、雨水口,化粪池,。。。ComponentMainType*/
int mSubType;/*子类型,就是页数。如果是井。WellSubType*/
int mExtraType;
std::wstring mExtraStr; //扩展
//...
};
//接口
struct Kernel_EXPORT ParamComponent
{
ParamComponent();
virtual ~ParamComponent();
//...
};
//利用模板来生成单例
template <
typename AbstractProduct, //接口
typename ProductTypeKey=std::wstring, //key
typename ...ArgTypes //其他参数
>
class GenericFactory
{
//.........
//得到具体的唯一实例
inline static GenericFactory<AbstractProduct, ProductTypeKey, ArgTypes...>& GetSingletonInstance()
{
static GenericFactory<AbstractProduct, ProductTypeKey, ArgTypes...> unique_generic_factory;
return unique_generic_factory;
}
};
//利用具体类型将模板进行实例化,通过继承生成类ParamComponentFactoryAtlasPageNo,并导出。
struct Kernel_EXPORT ParamComponentFactoryAtlasPageNo : public GenericFactory<ParamComponent, ObjectType>
{
//TestFactory() = delete;
//~TestFactory() = delete;
};
//利用同样的具体类型将模板进行实例化,通过继承生成类TestFac,并导出。
struct Kernel_EXPORT TestFac : public GenericFactory<ParamComponent, ObjectType>
{
//TestFactory() = delete;
//~TestFactory() = delete;
};
module2.dll里:
由于GenericFactory有接受注册的能力。现在用ParamComponentFactoryAtlasPageNo依次注册不同的类(对象),TestFac从不注册。:
void main()
{
ParamComponentFactoryAtlasPageNo::Register<ElbowParamComponent>(LINENAME(g_ParamComponent, __LINE__))(*ElbowParamComponent::GetStaticType());
auto& fac = ParamComponentFactoryAtlasPageNo::GetSingletonInstance();
auto& fac0 = TestFac::GetSingletonInstance();
会发现fac0里面并非为空,它和fac 的地址(&fac, &fac0)一样。而且里面也有内容,和ParamComponentFactoryAtlasPageNo里的一样,即使它从未进行过任何注册操作。
}
分析所导出的符号
用dumpins分析module1,发现导出的符号,并没有ParamComponentFactoryAtlasPageNo和TestFac,只有实例化后的:GenericFactory<ParamComponent, ObjectType>
用vs2015的开发人员命令提示
D:\DevTools\VS2015>dumpbin /exports D:\HchxKernel.dll >123567.txt
打开123567.txt:
发现导出了用ParamComponent, ObjectType实例化的类,导出了函数GetSingletonInstance(void)。没发现ParamComponentFactoryAtlasPageNo和TestFac的字样。
1、ParamComponentFactoryAtlasPageNo的构造函数(注意?0),TestFac类似:
245 F4 0000E8E0 ??0ParamComponentFactoryAtlasPageNo@@QEAA@XZ = @ILT+55515(??0ParamComponentFactoryAtlasPageNo@@QEAA@XZ)
2、ParamComponentFactoryAtlasPageNo的构造函数(注意?1),TestFac类似:
??1ParamComponentFactoryAtlasPageNo@@QEAA@XZ = @ILT+104295(??1ParamComponentFactoryAtlasPageNo@@QEAA@XZ)
3、被实例化之后模板,里面的接口GetSingletonInstance(void)
?$TSS0@?1??GetSingletonInstance@?$GenericFactory@UParamComponent@@UObjectType@@$$V@@SAAEAV2@XZ@4HA = ?$TSS0@?1??GetSingletonInstance@?$GenericFactory@UParamComponent@@UObjectType@@$$V@@SAAEAV2@XZ@4HA (int `public: static class GenericFactory<struct ParamComponent,struct ObjectType> & __cdecl GenericFactory<struct ParamComponent,struct ObjectType>::GetSingletonInstance(void)'::`2'::$TSS0)
4、unique_generic_factory是static的名字,被导出了。
?unique_generic_factory@?1??GetSingletonInstance@?$GenericFactory@UParamComponent@@UObjectType@@$$V@@SAAEAV2@XZ@4V2@A = ?unique_generic_factory@?1??GetSingletonInstance@?$GenericFactory@UParamComponent@@UObjectType@@$$V@@SAAEAV2@XZ@4V2@A (class GenericFactory<struct ParamComponent,struct ObjectType> `public: static class GenericFactory<struct ParamComponent,struct ObjectType> & __cdecl GenericFactory<struct ParamComponent,struct ObjectType>::GetSingletonInstance(void)'::`2'::unique_generic_factory)
可以发现,如果调用GetSingletonInstance,是只看实例化用的类型(ParamComponent, ObjectType),不看类名(ParamComponentFactoryAtlasPageNo和TestFac)
即使用namespace保护起来,其实只是给TestFac的构造和析构函数保护起来了。GetSingleInstance()所对应的还是那个。
所以在module2里面用auto& fac = NS_CREDCUnitTest::TestFac::GetSingletonInstance();,还是和ParamComponentFactoryAtlasPageNo::GetSingletonInstance();一样,里面有内容。
namespace NS_CREDCUnitTest
{
struct HCHXKernel_EXPORT TestFac : public GenericFactory<ParamComponent, ObjectType/*, std::string&*/>//, public Singleton<ParamComponentFactory>
{
//TestFactory() = delete;
//~TestFactory() = delete;
};
}
构造函数:
??0TestFac@NS_CREDCUnitTest@@QEAA@XZ = @ILT+87455(??0TestFac@NS_CREDCUnitTest@@QEAA@XZ)
析构函数:
??1TestFac@NS_CREDCUnitTest@@QEAA@XZ = @ILT+36135(??1TestFac@NS_CREDCUnitTest@@QEAA@XZ)
更有意思的:
而且在module2里面,即使你定义一个类继承自GenericFactory<ParamComponent, ObjectType>,不做import或者export,最后GetSingleInstance引用的结果还是ParamComponentFactoryAtlasPageNo::GetSingleInstance()一样。相当奇特啊。
struct RebarComponentFactory : public GenericFactory<ParamComponent, ObjectType>
{
//TestFactory() = delete;
//~TestFactory() = delete;
};