动态库中模版类的导出问题综述
作者:lovebzhou lovebzhou@gmail.com 2006-11-16
摘要:模版是OO的另一种解决之道,增加了效率与类型安全。动态库作为模块和组件的载体,增加了应用配置的灵活性。本文记录了动态库中导出模版类的相关问题,但并未作过深的讨论,其中涉及了STL和ACE的相关内容,但他们无关紧要。
关键字:动态库、模版类、导入、导出、对象工厂
问题描述:本文介绍的是在我的一个小项目中的一个可复用对象工厂模版类,作为协议栈模块消息体对象工厂时遇到的一些问题。我要把协议栈消息体工厂作为几个相关模块的共享对象,其他服务在其相应的模块中实现自己的消息体,然后将服务类型和各自的创建函数注册到这个工厂中。这个模版对象工厂非常通用,所以我不想将他全特化(这意味着所有的东西我都要重写),这也就无法具现化这个类,也就无法将他导出。
这个对象工厂像下面这个样子:
#ifndef FACTORY_IMPL_T_H
#define
FACTORY_IMPL_T_H

#include
"
ace/Synch.h
"
#include
"
ace/Map_Manager.h
"

template
<
class
Product, typename ID
>
class
FactoryErrorPolicy
{
protected:
Product OnUnknownType(const ID &id);
}
;
template
<
class
Product, typename ID, typename Creator,
class
ACE_LOCK
=
ACE_Null_Mutex
>
class
Factory_Impl :
public
FactoryErrorPolicy
<
Product, ID
>
{
public:
bool Register(const ID &id, Creator creator);
bool Unregister(const ID &id);
Product CreateObject(const ID &id);
protected:
Factory_Impl();
private:
typedef ACE_Map_Manager<ID, Creator, ACE_LOCK> AssocMap;
AssocMap repository_;
}
;
#include
"
Factory_Impl_T.cpp
"

#endif
//
FACTORY_IMPL_T_H
这个对象工厂的实现很简单,无非是MAP的插入、删除和查找操作。这个文件不属于任何模块,所以应将他放在一个容易引用的位置上。
模版导出: 这多少有些误解,模版怎么导出?在真正使用之前编译器不会为它产生任何代码,所以这里所谓的模版导出指的是一个具体的特化版本。在使用这个对象工厂的模块中,这个特化版本已经确定。然而这里我们遇到的问题是:特化就意味着我们要重新实现模版的所有方法,这不是我们期望的。解决方式很简单,通过一个间接类便可以了,过多口舌不如代码,示例如下:
///...
/// SRPC_Msg_Body抽象类,服务模块通过继承这个类定义自己相应消息体
typedef Sptr<SRPC_Msg_Body> (*DefaultCreator)();
#include "inc/Factory_Impl_T.h"

ACE_TEMPLATE_SPECIALIZATION
class FactoryErrorPolicy<Sptr<SRPC_Msg_Body>, ACE_UINT32>
{
protected:
Sptr<SRPC_Msg_Body> OnUnknownType(const ACE_UINT32 &id);
}
;
typedef Factory_Impl
<Sptr<SRPC_Msg_Body>, ACE_UINT32, DefaultCreator> __BodyFactory;
class SRPC_Export BodyFactory : public __BodyFactory
{
friend class ACE_Singleton<BodyFactory, ACE_SYNCH_MUTEX>;
public:
static BodyFactory* instance()
{
return ACE_Singleton<BodyFactory, ACE_SYNCH_MUTEX>::instance();
}
private:
BodyFactory();
BodyFactory(const BodyFactory &);
BodyFactory& operator=(const BodyFactory &);
}
;
///...
红字代码:就是这里的解决之道(对象工厂应该是唯一的,所以顺便加上了singleton)。
SRPC_Export:编译指示符宏,用于导出或导入对象工厂及相关类。
绿色斜体字部分:特化错误处理,这里跑出SRPC_Exception异常。
应用示例:
/// DLL中:
/// 不依赖具体消息体
int
SRPC_Message::decode(ACE_Message_Block
*&
data)
{
/// the implementation is not quite reasonable, it assume that
/// the buffer has two sections. one is message header, the other is
/// message body.
header_->decode(data);
body_ = BodyFactory::instance()->CreateObject(header_->service());
ACE_Message_Block *mb = data->cont();
body_->decode(mb);
return 0;
}

///调用模块中:
namespace
{
Sptr<SRPC_Msg_Body> make_RegisterBody()
{
/// Message_Body_Register继承自Message_Body
return new Message_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.
本文探讨了在动态库中导出模版类的具体实践,包括如何通过特化解决导出问题,以及如何利用ACE库实现线程安全的对象工厂。


6675

被折叠的 条评论
为什么被折叠?



