qiezi的学习园地

AS/C/C++/D/Java/JS/Python/Ruby

  C++博客 :: 首页 :: 新随笔 ::  ::  :: 管理 ::
很久以前看到有人问“如何在C++中实现动态加载类”时,简单地做了一个。

不过当时没有去考虑动态加载DLL的情况。

今天在cpp@codingnow.com中也有人问到这个问题,就把它给做完了。

当然只是简单地做到了“从全局类型库中,根据类名创建实例,支持动态DLL加载”,说得更明白点:

在应用程序App1中,向全局类型库中注册一个类型"Test",在另一个隐式链接的DLL中(即App1一启动就加载的DLL),向全局类型库中注册另外几个类型。这时可以在App1中通过类型的名字生成实例。

在另一个显式加载的DLL中(即调用LoadLibrary加载),向全局类型库中注册其它几个类型。这时通过LoadLibrary加载这个DLL,就可以生成这几个类型的实例了。

这地方不能上传文件,就把代码贴一点吧:

typelib.h文件:

#ifndef __TYPE_LIB_H__
#define __TYPE_LIB_H__

typedef 
void*(*CREATE_FUNC)();
typedef 
void(*RELEASE_FUNC)(void*);

void regtype (const char* name, CREATE_FUNC cfunc, RELEASE_FUNC rfunc);

void* createObject (const char* name);

void releaseObject (const char* name, void* p);

struct ITestInterface
{
    
virtual ~ITestInterface () {}
    
virtual void print () const = 0;
};

template 
<class T>
void* create ()
{
    
return new T;
}

template 
<class T>
void release (void* p)
{
    delete (T
*)p;
}

#endif // __TYPE_LIB_H__

typelib.cpp文件:

#include "typelib.h"

#include 
<string>
#include 
<map>
using namespace std;

namespace TypeRegistry
{
    
static map < string, pair<CREATE_FUNC, RELEASE_FUNC> >  types_info;

    template 
<class T>
    
void regType (const string& name)
    {
        types_info.insert (make_pair(name, make_pair(create
<T>, release<T>)));
    }
}

void regtype (const char* name, CREATE_FUNC cfunc, RELEASE_FUNC rfunc)
{
    TypeRegistry::types_info.insert (make_pair(name, make_pair(cfunc, rfunc)));
}

void* createObject (const char* name)
{
    map 
< string, pair<CREATE_FUNC, RELEASE_FUNC> >::const_iterator iter;
    iter 
= TypeRegistry::types_info.find (name);
    
if (iter != TypeRegistry::types_info.end ())
        
return (*iter->second.first)();
    
return NULL;
}

void releaseObject (const char* name, void* p)
{
    map 
< string, pair<CREATE_FUNC, RELEASE_FUNC> >::const_iterator iter;
    iter 
= TypeRegistry::types_info.find (name);
    
if (iter != TypeRegistry::types_info.end ())
        (
*iter->second.second)(p);
}

把它编译成静态lib或DLL,就可以使用了。

在那2个为我们提供类型的DLL中,DllMain函数中加入下面的代码:

// FirstTest和SecondTest是2个类名
regtype("FirstTest", create<FirstTest>, release<FirstTest>);
regtype(
"FirstTest", create<SecondTest>, release<SecondTest>);

就可以向全局类型库中注册类型。注意在类型库中是没有保存类信息的,所以最好是使用单根类库来做。

下面是一点测试代码:

int main()
{
       
// 程序启动时注册类型。
       
// 实际上启动时就加载了另一个动态链接库,那里面有3个类型,所以现在有4个类型
       regtype ("MyTest", create<MyTest>, release<MyTest>);
       
while (1)
       {
               
string class_name;
               cin 
>> class_name;
               
if (class_name == "q")
                       
break;
               
// 当输入load时,把另一个动态链接库加载进来,那个链接库中有2个类型,现在共有6个类型可用。
               if (class_name == "load")
               {
                       LoadLibrary(
"typelibdll_test.dll");
                       
continue;
               }
               ITestInterface
* test = (ITestInterface*)createObject (class_name.c_str());
               
if (!test)
               {
                       cout 
<< "This type not found" << endl;
                       
continue;
               }
               test
->print ();
               releaseObject (class_name.c_str(), test);
       }
       
return 0;
}

还有一个没考虑的地方,就是没有给它加锁,因为有可能在一个线程中加载一个DLL。

不过我还有些怀疑这东西是否真的有用?
posted on 2005-09-26 17:31 qiezi 阅读(1065) 评论(11)  编辑 收藏 引用 所属分类: 自家破烂C++