因为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