动态库中模版类的导出问题综述介绍
动态库中模版类的导出问题综述
作者:lovebzhou lovebzhou@gmail.com 2006-11-16
摘要:模版是OO的另一种解决之道,增加了效率与类型安全。动态库作为模块和组件的载体,增加了应用配置的灵活性。本文记录了动态库中导出模版类的相关问题,但并未作过深的讨论,其中涉及了STL和ACE的相关内容,但他们无关紧要。
关键字:动态库、模版类、导入、导出、对象工厂
问题描述:本文介绍的是在我的一个小项目中的一个可复用对象工厂模版类,作为协议栈模块消息体对象工厂时遇到的一些问题。我要把协议栈消息体工厂作为几个相关模块的共享对象,其他服务在其相应的模块中实现自己的消息体,然后将服务类型和各自的创建函数注册到这个工厂中。这个模版对象工厂非常通用,所以我不想将他全特化(这意味着所有的东西我都要重写),这也就无法具现化这个类,也就无法将他导出。
这个对象工厂像下面这个样子:
#defineFACTORY_IMPL_T_H
#include"ace/Synch.h"
#include"ace/Map_Manager.h"
template<classProduct,typenameID>
classFactoryErrorPolicy
{
protected:
ProductOnUnknownType(constID&id);
};
template<classProduct,typenameID,typenameCreator,classACE_LOCK=ACE_Null_Mutex>
classFactory_Impl:publicFactoryErrorPolicy<Product,ID>
{
public:
boolRegister(constID&id,Creatorcreator);
boolUnregister(constID&id);
ProductCreateObject(constID&id);
protected:
Factory_Impl();
private:
typedefACE_Map_Manager<ID,Creator,ACE_LOCK>AssocMap;
AssocMaprepository_;
};
#include"Factory_Impl_T.cpp"
#endif//FACTORY_IMPL_T_H
这个对象工厂的实现很简单,无非是MAP的插入、删除和查找操作。这个文件不属于任何模块,所以应将他放在一个容易引用的位置上。
模版导出:这多少有些误解,模版怎么导出?在真正使用之前编译器不会为它产生任何代码,所以这里所谓的模版导出指的是一个具体的特化版本。在使用这个对象工厂的模块中,这个特化版本已经确定。然而这里我们遇到的问题是:特化就意味着我们要重新实现模版的所有方法,这不是我们期望的。解决方式很简单,通过一个间接类便可以了,过多口舌不如代码,示例如下:///SRPC_Msg_Body抽象类,服务模块通过继承这个类定义自己相应消息体
typedefSptr<SRPC_Msg_Body>(*DefaultCreator)();
#include"inc/Factory_Impl_T.h"
ACE_TEMPLATE_SPECIALIZATION
classFactoryErrorPolicy<Sptr<SRPC_Msg_Body>,ACE_UINT32>
{
protected:
Sptr<SRPC_Msg_Body>OnUnknownType(constACE_UINT32&id);
};
typedefFactory_Impl<Sptr<SRPC_Msg_Body>,ACE_UINT32,DefaultCreator>__BodyFactory;
classSRPC_ExportBodyFactory:public__BodyFactory
{
friendclassACE_Singleton<BodyFactory,ACE_SYNCH_MUTEX>;
public:
staticBodyFactory*instance()
{
returnACE_Singleton<BodyFactory,ACE_SYNCH_MUTEX>::instance();
}
private:
BodyFactory();
BodyFactory(constBodyFactory&);
BodyFactory&operator=(constBodyFactory&);
};
///...
红字代码:就是这里的解决之道(对象工厂应该是唯一的,所以顺便加上了singleton)。
SRPC_Export:编译指示符宏,用于导出或导入对象工厂及相关类。
绿色斜体字部分:特化错误处理,这里跑出SRPC_Exception异常。
应用示例:
///不依赖具体消息体
intSRPC_Message::decode(ACE_Message_Block*&data)
{
///theimplementationisnotquitereasonable,itassumethat
///thebufferhastwosections.oneismessageheader,theotheris
///messagebody.
header_->decode(data);
body_=BodyFactory::instance()->CreateObject(header_->service());
ACE_Message_Block*mb=data->cont();
body_->decode(mb);
return0;
}
///调用模块中:
namespace
{
Sptr<SRPC_Msg_Body>make_RegisterBody()
{
///Message_Body_Register继承自Message_Body
returnnewMessage_Body_Register;
}
}
Unit_Test::Unit_Test()
{
///注册消息体创建函数
BodyFactory::instance()->Register(SERVICE_ID,make_RegisterBody);
}
Unit_Test::~Unit_Test()
{
///解注册服务和注册消息体
BodyFactory::instance()->Unregister(SERVICE_ID);
}
相关问题:
这里用ACE_Map_Manager是有原因的,STL中的map在这里会失败(在非模版导出类没问题),原因未查。另外:ACE_Map_Manager的应用使得这个对象工厂可灵活增加线程安全机制。
参考文献:
[1] Andrei Alexandrescu. Modern C++ Design: Generic Programming and Design Patterns Applied. Addison-Wesley, Boston, 2001.
[2]马维达, ACE中文参考文集.chm ,2002.
本文地址:http://www.45fan.com/dnjc/71042.html