C ++插件系统,插件继承自基类

时间:2017-03-15 14:17:45

标签: c++ inheritance plugins api-design

我正在尝试为我的C ++代码库添加插件功能。由于插件需要包含插件编写者不应该知道的管道(因此保持包含文件简单),因此出现了困难。 所以,这是设置:

" PluginBase.h&#34 ;.这是插件将继承的类。

class PluginBase {
  virtual void PluginProcess() = 0; // the plugin-specific capability 
};

" PluginPlumbing.h&#34 ;.包含管道的类。

class PluginPlumbing : public PluginBase {
  void PlumbingFunction() {
    // Some stuff
    PluginProcess();
    // Some more stuff
  }
};

外部框架代码(通过加载插件的DLL /)获取指向PluginPlumbing类实例的指针,然后在其上调用PlumbingFunction()。

然而,我遇到的难题是,我不能将我从DLL中获得的PluginBase指针向上转换为PluginPlumbing指针,因为它显然不会从PluginPlumbing继承。而且我无法从PluginPlumbing继承插件,因为我回到了将插件暴露给插件编写器的方方面面。

我能想象的唯一解决方案是,PluginBase和PluginPlumbing完全是独立的类,而不是很好地继承。 PluginBase将由DLL / so实例化,PluginPlumbing实例将由框架实例化,并传递PluginBase指针,以便它可以进行管道调用。这是解决问题的唯一解决方案吗?

1 个答案:

答案 0 :(得分:0)

如果您想将插件中的某些功能暴露给外部软件,您必须提供一些接口。

在您的示例中,您提供了PluginBasePluginProcess()函数的接口,因此,PluginBase接口的任何其他用户都可以调用它而无需关心其实现。

如果你需要另一个接口与另一个方法 - 以同样的方式做。

class PluginPlumbing {
public:
    virtual void PlumbingFunction() = 0;
};

隐藏DLL实现中的实现:

class PluginPlumbingImpl : public PluginPlumbing {
public:
    void PlumbingFunction() override {
       // do the stuff
    }
}

如果需要其他参数 - 也将其作为抽象接口类或POD结构传递。你还应该为你的插件函数做一些声明,它将为你的接口实现创建精确的实例(插件的用户应该可以访问它)。

总结一下,你应该有类似的东西:

// myplugininterface.h
// this header will be exposed to plugin implementors and
// plugin consumers

class IMyPluginClass1 {
public:
    virtual void func1() = 0;
    virtual void func2() = 0;
}

// another interface, ties together other functionality
class IMyPluginClass2 {
public:
    virtual void func1() = 0;
    // you can even pass around your interface classes
    virtual void doSomethingWithAnotherObject(IMyPluginClass1 *obj) = 0;

    // or use "factory" methods to create objects
    virtual IMyPluginClass1 *createObject() = 0;
}

// this is functions implemented by a plugins, they should create
// instances for your plugin objects
// you could do them as a static methods of your classes if you don't
// plan to expose that as C compatible plugins
IMyPluginClass1 *createObject1();
IMyPluginClass2 *createObject2();


// mycoolplugin.cpp
// specific implementation of your plugin, you or someone else
// compile this to plugin DLL

#include "myplugininterface.h"

class IMyPluginClass1Impl : public IMyPluginClass1 {
public:
    IMyPluginClass1Impl() :
        myMyValue(100500)
    {}

    void func1() override {
        // implement
    }
    void func2() override {
        // implement
    }
private:
    // you can have any private or even public members in your implementation
    int mMyValue;
};

class IMyPluginClass2Impl : public IMyPluginClass2 {
public:
    void func1() override {
        // implement
    }

    void doSomethingWithAnotherObject(IMyPluginClass1 *obj) override {
        // implement
        // but don't assume you can cast IMyPluginClass1 to
        // something specific, because it might be not yours implementation
        // it depends on how carefully you design your interfaces and
        // explain to plugin writers what is allowed and what is not
    }

    IMyPluginClass1 *createObject() {
        // be careful with that, in that case you MUST declare
        // virtual destructor as a part of your interface class
        return new IMyPluginClass1Impl();
    }
};

IMyPluginClass1 *createObject1() {
    return new IMyPluginClass1Impl();
}
IMyPluginClass2 *createObject2() {
    return new IMyPluginClass2Impl();
}

您插件的用户只能通过加入myplugininterface.h和来使用它 获取create函数的地址(这取决于平台)。

请记住,如果您返回new创建的实例并允许 您的插件的用户是delete这样创建的对象 - 您必须这样做 为您的接口类声明虚拟析构函数。

这是一种通用方法。当你有层次结构时,它有一些陷阱 你的插件对象,你不能分享你的摘要的常见实现 没有付出额外努力的课程(假设你不想拥有copypasta)