动态库中模版类的导出问题综述

本文探讨了在动态库中导出模版类的具体实践,包括如何通过特化解决导出问题,以及如何利用ACE库实现线程安全的对象工厂。

动态库中模版类的导出问题综述

作者:lovebzhou lovebzhou@gmail.com 2006-11-16

摘要:模版是OO的另一种解决之道,增加了效率与类型安全。动态库作为模块和组件的载体,增加了应用配置的灵活性。本文记录了动态库中导出模版类的相关问题,但并未作过深的讨论,其中涉及了STLACE的相关内容,但他们无关紧要。

关键字:动态库、模版类、导入、导出、对象工厂

问题描述:本文介绍的是在我的一个小项目中的一个可复用对象工厂模版类,作为协议栈模块消息体对象工厂时遇到的一些问题。我要把协议栈消息体工厂作为几个相关模块的共享对象,其他服务在其相应的模块中实现自己的消息体,然后将服务类型和各自的创建函数注册到这个工厂中。这个模版对象工厂非常通用,所以我不想将他全特化(这意味着所有的东西我都要重写),这也就无法具现化这个类,也就无法将他导出。

这个对象工厂像下面这个样子:

#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.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值