我有my_program
加载了一些共享库。基本上,用户可以创建一个项目,然后可以使用my_program
执行该项目。我想从共享库加载类。我找到了以下示例:C++ Dynamic Shared Library on Linux
这个例子很棒,但是我有一个问题。我没有头文件。
那么,有没有什么方法可以加载我没有头文件的类?我想没有。
如果我没记错的话,我不认为有一种动态加载头文件的方法吗?
如果用户写class Child : public Parent
,那么在我的主程序中,我必须用Child替换MyClass
(根据我提供的示例)。我知道子类中有哪些方法,例如我为BaseParent
类提供了纯虚拟方法。因此,我将在主程序中包含BaseParent
。但是我仍然需要知道这个项目的类名。
如果我说项目类名称必须始终为MY_PROJECT怎么办?有帮助吗?
然后我知道我必须用MyClass
替换MY_PROJECT
(来自上面的示例),但是那不会触发错误,因为主程序对类MY_PROJECT
一无所知吗?
我愿意接受任何建议,因为我确实被卡住了。
编辑:
如果我有这个类在主程序中:
class BaseParent
{
public:
virtual bool init(const TestCase&);
virtual void run();
virtual bool done();
}
接下来的两个类由创建项目的用户编写
class Parent : public BaseParent
{
public:
bool init(const TestCase &test)
{
//implementation of this method
}
void run()
{
execute(.....);
}
bool done()
{
//implementation of this method
}
//he must also define this method which is in child class
virtual void execute(...);
};
和另一类
class Child : public Parent
{
public:
void execute(...)
{
//implementation of this method
}
};
extern "C" Child* create_object()
{
return new Child;
}
extern "C" void destroy_object( Child* object )
{
delete object;
}
因此,我只能在主程序中包含
BaseParent
。如果Child类返回指向BaseParent
的指针,那么我可以像下面这样调用init,done和run之类的方法?甚至那个BaseParent
都不知道在运行中调用哪个execute?void *handle = dlopen(shared_lib, RTLD_LAZY);
if (handle)
{
BaseParent* (*create)();
void (*destroy)(BaseParent*);
create = (BaseParent* (*)())dlsym(handle, "create_object");
destroy = (void (*)(BaseParent*))dlsym(handle, "destroy_object");
BaseParent* myClass = (BaseParent*)create();
myClass->init(test); //wouldn this trigger an error because it's not implemented in BaseParent but in Child?
}
编辑2:
BaseParent* (*create)();
void (*destroy)(BaseParent*);
//other code.... buff is path to libProject.so
void *handle = dlopen(buff, RTLD_LAZY);
if (handle)
{
create = (BaseParent* (*)())dlsym(handle, "create_object");
destroy = (void(*)(BaseParent*))dlsym(handle, "destroy_object");
BaseParent *a = (BaseParent*)create();
a->run();
}else
{
LOG(ERROR) << "Error in opening lib " << buff;
return;
}
问题是链接器(在OS X上)给我一个错误:
Undefined symbols for architecture x86_64:
"BaseParent::run()", referenced from:
vtable for BaseParent in BaseParent
"BaseParent::init(TestCase&)", referenced from:
vtable for BaseParent in BaseParent
ld: symbol(s) not found for architecture x86_64
但是在Ubuntu 12.04上我得到了:
(gdb)
99 AbsAlgorithm *a = (AbsAlgorithm*)create();
(gdb)
Program received signal SIGSEGV, Segmentation fault.
0x0000000000000000 in ?? ()
因此,如上所示,该run和init方法是虚拟的。有什么建议吗?
最佳答案
UPD:我认为最正确的是
extern "C" BaseParent* create_object()
{
return new Child;
}
因此,您可以保留
Child
完全存在于用户库中的事实,并且可以完全根据BaseParent
提供库接口。进行此更正后,此代码将起作用(只要它不包含其他错误,就不会检查其可编译性)。基本上,这就是多态性的关键思想:如果您有一个基类(接口)并且有一个派生类,并且某些代码仅使用该接口的方法,则该代码不需要知道有关该派生类的任何详细信息。 ,甚至都不知道派生类的存在。所有代码需要的是指向对象的指针,从该代码的角度来看,该指针将具有类似
Interface*
的类型,即将成为指向接口的指针。