我有my_program
加载一些共享库。 Basicaly用户可以创建一个项目,然后可以使用my_program
执行该项目。我想从共享库加载类。我找到了这个例子:C++ Dynamic Shared Library on Linux
这个例子很棒,但我遇到了问题。我没有头文件。 那么,是否有任何可能的方法来加载我没有头文件的类?我想没有。 如果我没有弄错,我不认为有办法动态加载头文件吗?
如果用户写class Child : public Parent
,那么在我的主程序中,我必须将MyClass
(来自我提供的示例)替换为Child。我知道Child类中有哪些方法,因为我提供了BaseParent
类的纯虚方法。所以我会在我的主程序中加入BaseParent
。但我仍然需要知道这个项目的类名。
如果我说项目类名称必须始终为MY_PROJECT怎么办?那会有帮助吗?
然后我知道我必须用MyClass
替换MY_PROJECT
(来自上面的示例)但不会触发错误,因为主程序对类{{1}一无所知}?
我愿意接受任何建议,因为我确实被卡住了。
编辑: 如果我有这个课程在主程序中:
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;
}
。如果Child类返回指向BaseParent
的指针,那么我可以调用init,done和run这样的方法吗?即使BaseParent
不知道在运行中调用的执行?
BaseParent
编辑2:
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?
}
问题是链接器(在OS X上)给我一个错误:
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;
}
但是在Ubuntu 12.04上我得到了这个:
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
因此,如上所示,run和init方法是虚拟的。有什么建议吗?
答案 0 :(得分:1)
UPD :我认为最正确的是
extern "C" BaseParent* create_object()
{
return new Child;
}
因此,您要确保Child
完全存在于用户的库中,并且您完全按照BaseParent
提供库界面。
通过此更正,此代码将起作用(只要它不包含其他错误,我没有检查它的可编译性)。基本上这是多态的关键思想:如果你有一个基类(接口)并且你有一个派生类,而某些代码只使用接口的方法,那么该代码不需要知道派生类的任何细节,甚至都不知道派生类是否存在。所有代码需要的是指向对象的指针,从该代码的角度来看,这个指针的类型为Interface*
,即将指向接口。