dlopen加载C++对象

因为C++里有函数名重组,所以函数可以重载,但也导致dlopen不能加载C++的函数,更不能加载C++的对象了. 一种好的解决方案就是利用C++的多态,定义好接口基类,在so文件中继承基类,实现实际干活的子类, 并在so文件中创建好工厂函数,工厂函数使用C语言实现,以便主程序能找到.

参考一些外文博客,采用接口自动注册的方式,更为便捷.下面是具体代码:

role.h文件:

#ifndef __ROLE_H__
#define __ROLE_H__

#include <string>
#include <map>
class Role
{
public:
    virtual int set_name(const std::string& name) = 0;
    virtual const std::string& get_name() const = 0;
    virtual int process() = 0;
};

typedef Role* (*new_func_t)();
extern std::map<std::string, new_func_t> g_factory;

#endif //__ROLE_H__

这里的g_factory是主程序定义的一个全局的记录接口函数指针的变量.

searcher.h文件,一个具体的实现:

#ifndef __SEARCHER_H__
#define __SEARCHER_H__

#include "role.h"
class Searcher : public Role
{
public:
    int set_name(const std::string& name);
    const std::string& get_name() const;
    int process();
private:
    std::string name_;
};

#endif //__SEARCHER_H__

searcher.cpp文件:

#include "searcher.h"
#include <iostream>

int Searcher::set_name(const std::string& name)
{
    name_ = name;
    return 0;
}   

const std::string& Searcher::get_name() const
{
    return name_;
}

int Searcher::process()
{
    std::cout << name_ << " is working" << std::endl;
    return 0;
}

extern "C" {
Role *new_searcher()
{
    return new Searcher();
}
class SearcherRegister
{
public:
    SearcherRegister()
    {
        g_factory["Searcher"] = new_searcher;
    }
};
SearcherRegister searcher_register;
}

这里利用class SearcherRegister的构造函数,进行自动注册接口函数.new_searcher函数用于创建一个Searcher对象.

以上三个文件,就是so文件的全部,编译命令:

g++ searcher.cpp -I./ -fPIC -shared -o role.so

main.cpp文件是主程序代码,加载并使用Searcher对象:

#include <iostream>
#include <string>
#include <map>
#include <dlfcn.h>
#include "role.h"
using namespace std;

map<string, new_func_t> g_factory;

int main()
{
    void *role_so = dlopen("./role.so", RTLD_NOW | RTLD_GLOBAL);
    if (role_so == NULL) {
        cout << dlerror() << endl;
        return -1; 
    }   
    if (g_factory["Searcher"]) {
        Role *searcher = g_factory["Searcher"]();
        searcher->set_name("searcher");
        searcher->process();
        delete searcher;
    }   
    dlclose(role_so);
    return 0;
}

如上面的代码,g_factory在主程序中创建.g_factory["Searcher"]()就创建了一个Searcher对象了,注意产生的对象一定需要使用delete进行释放,不然就会导致内存泄漏了.

编译命令如下:

g++ main.cpp -o run -I./ -ldl -rdynamic

注意,-rdynamic用于将主程序的符号表对so文件敞开,否则程序执行会报如下错误,就是因为role.so找不到主程序里的g_factory:

./role.so: undefined symbol: g_factory
发表于 2015年01月25日 23:20   评论:0   阅读:3316  



回到顶部

首页 | 关于我 | 关于本站 | 站内留言 | rss
python logo   django logo   tornado logo