从没有头文件

时间:2015-07-23 12:58:34

标签: c++ c++11 shared-libraries

我有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方法是虚拟的。有什么建议吗?

1 个答案:

答案 0 :(得分:1)

UPD :我认为最正确的是

extern "C" BaseParent* create_object()
{
  return new Child;
}

因此,您要确保Child完全存在于用户的库中,并且您完全按照BaseParent提供库界面。

通过此更正,此代码将起作用(只要它不包含其他错误,我没有检查它的可编译性)。基本上这是多态的关键思想:如果你有一个基类(接口)并且你有一个派生类,而某些代码只使用接口的方法,那么该代码不需要知道派生类的任何细节,甚至都不知道派生类是否存在。所有代码需要的是指向对象的指针,从该代码的角度来看,这个指针的类型为Interface*,即将指向接口。