从没有头文件的共享库加载 class
Load class from shared library without header file
我有 my_program
加载一些共享库。基本上用户可以创建一个项目,然后可以使用 my_program
执行该项目。我想从共享库加载 class。我找到了这个例子:C++ Dynamic Shared Library on Linux
这个例子很好,但我有一个问题。我没有头文件。
那么,有什么可能的方法来加载我没有头文件的 class 吗?我想没有。
如果我没记错的话,我认为没有办法动态加载头文件?
如果用户写 class Child : public Parent
那么在我的主程序中我必须用 Child 替换 MyClass
(来自我提供的那个例子)。我知道 Child class 中有哪些方法,因为我为 BaseParent
class 提供了纯虚拟方法。所以我会在我的主程序中包含 BaseParent
。但我仍然需要知道这个项目的 class 名称。
如果我说项目 class 名称必须始终是 MY_PROJECT 怎么办?那会有帮助吗?
然后我会知道我必须用 MY_PROJECT
替换 MyClass
(来自上面的示例)但是不会触发错误因为主程序对 class [=25= 一无所知]?
我愿意接受任何建议,因为我确实被困住了。
编辑:
如果我在主程序中有这个 class:
class BaseParent
{
public:
virtual bool init(const TestCase&);
virtual void run();
virtual bool done();
}
接下来的两个class是创建项目的用户写的
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
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 class return 指向 BaseParent
的指针,那么我可以像下面这样调用 init、done 和 运行 等方法吗?即使 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 ?? ()
因此,运行 和 init 方法是虚拟的,如上所示。有什么建议吗?
UPD:我认为最正确的是
extern "C" BaseParent* create_object()
{
return new Child;
}
所以你保留 Child
完全存在于用户库中的事实,并且你完全根据 BaseParent
.
提供库接口
通过这个更正,这段代码可以工作(只要它不包含其他错误,我没有检查它的可编译性)。基本上这是多态性的关键思想:如果你有一个基础 class(接口)并且你有一个派生的 class,并且一些代码只使用接口的方法,那么该代码不需要知道有关派生 class 的任何细节,甚至根本不知道派生 class 的存在。所有代码需要的是指向对象的指针,从该代码的角度来看,该指针的类型类似于 Interface*
,即指向接口的指针。
我有 my_program
加载一些共享库。基本上用户可以创建一个项目,然后可以使用 my_program
执行该项目。我想从共享库加载 class。我找到了这个例子:C++ Dynamic Shared Library on Linux
这个例子很好,但我有一个问题。我没有头文件。 那么,有什么可能的方法来加载我没有头文件的 class 吗?我想没有。 如果我没记错的话,我认为没有办法动态加载头文件?
如果用户写 class Child : public Parent
那么在我的主程序中我必须用 Child 替换 MyClass
(来自我提供的那个例子)。我知道 Child class 中有哪些方法,因为我为 BaseParent
class 提供了纯虚拟方法。所以我会在我的主程序中包含 BaseParent
。但我仍然需要知道这个项目的 class 名称。
如果我说项目 class 名称必须始终是 MY_PROJECT 怎么办?那会有帮助吗?
然后我会知道我必须用 MY_PROJECT
替换 MyClass
(来自上面的示例)但是不会触发错误因为主程序对 class [=25= 一无所知]?
我愿意接受任何建议,因为我确实被困住了。
编辑: 如果我在主程序中有这个 class:
class BaseParent
{
public:
virtual bool init(const TestCase&);
virtual void run();
virtual bool done();
}
接下来的两个class是创建项目的用户写的
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
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 class return 指向 BaseParent
的指针,那么我可以像下面这样调用 init、done 和 运行 等方法吗?即使 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 ?? ()
因此,运行 和 init 方法是虚拟的,如上所示。有什么建议吗?
UPD:我认为最正确的是
extern "C" BaseParent* create_object()
{
return new Child;
}
所以你保留 Child
完全存在于用户库中的事实,并且你完全根据 BaseParent
.
通过这个更正,这段代码可以工作(只要它不包含其他错误,我没有检查它的可编译性)。基本上这是多态性的关键思想:如果你有一个基础 class(接口)并且你有一个派生的 class,并且一些代码只使用接口的方法,那么该代码不需要知道有关派生 class 的任何细节,甚至根本不知道派生 class 的存在。所有代码需要的是指向对象的指针,从该代码的角度来看,该指针的类型类似于 Interface*
,即指向接口的指针。