从没有头文件的共享库加载 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*,即指向接口的指针。