问题描述
我想在运行时加载库。我有一个基类“ Base”和两个派生类“ Derived1”和“ Derived2”,应在运行时加载它们。我正在使用this answer中的方法进行一些小的修改。当我仅定义一个派生类时,代码可以完美地编译,但是当定义多个派生类时,代码将无法编译。编译错误如下:
multiple deFinitions of 'create'
我认为问题是“ C”不允许重载函数名称。一个人将如何解决这个问题?
重要的一点是,由于我不知道存在多少.so
个文件,因此我想为所有.so
个文件使用一个处理程序。代码的详细信息如下:
base.hpp
:
class Base {
public:
virtual ~Base() {}
virtual void foo() const = 0;
};
using Base_creator_t = Base *(*)();
derived1.hpp
:
#include "Interface.hpp"
class Derived1: public Base {
public:
void foo() const override {}
};
extern "C" {
Base * create() {
return new Derived1;
}
}
derived2.hpp
:
#include "Interface.hpp"
class Derived2: public Base {
public:
void foo() const override {}
};
extern "C" {
Base * create() {
return new Derived2;
}
}
动态共享库处理程序:Derived_factory.hpp
:
#include <dlfcn.h>
class Derived_factory {
public:
Derived_factory(char* path) {
handler = dlopen(path,RTLD_Now);
if (! handler) {
throw std::runtime_error(dlerror());
}
Reset_dlerror();
creator = reinterpret_cast<Base_creator_t>(dlsym(handler,"create"));
Check_dlerror();
}
std::unique_ptr<Base> create() const {
return std::unique_ptr<Base>(creator());
}
~Derived_factory() {
if (handler) {
dlclose(handler);
}
}
private:
void * handler = nullptr;
Base_creator_t creator = nullptr;
static void Reset_dlerror() {
dlerror();
}
static void Check_dlerror() {
const char * dlsym_error = dlerror();
if (dlsym_error) {
throw std::runtime_error(dlsym_error);
}
}
};
main.cpp
:
#include "Derived_factory.hpp"
int main(){
Derived_factory factoryOne("Derived1.so");
std::unique_ptr<Base> baSEOne = factoryOne.create();
baSEOne->foo();
Derived_factory factoryTwo("Derived2.so");
std::unique_ptr<Base> baseTwo = factoryTwo.create();
baseTwo->foo();
return 0;
}
解决方法
问题不是ncpus=3
。问题是您有同一个函数的多个定义。
extern "C"
与Base * create()
您想要做的是在两个不同的可加载模块中具有相同的功能。但是,您要做的是将该函数的两个实现(具有相同的名称和签名!)放入主模块,这当然会导致多个定义错误。
您应该做的是将create
函数放入*.cpp
文件中,即derived1.cpp
和derived2.cpp
,从*.hpp
文件中省略它们的定义,然后从这些*.cpp
文件中编译共享对象。我已经修改了您的项目以实现此目标,请参见live demo。