简体   繁体   English

C ++插件系统,其中插件从基类继承

[英]C++ plugin system where the plugins inherit from base class

I am trying to add a plugin capability to my C++ codebase. 我正在尝试向我的C ++代码库添加插件功能。 The difficulty arises because the plugins need to contain plumbing the plugin writer shouldn't be aware of (thus keeping the include file simple). 出现困难的原因是,插件需要包含管道,插件编写者不应该知道(因此,使包含文件保持简单)。 So, this is the setup: 因此,这是设置:

"PluginBase.h". “PluginBase.h”。 This is the class the plugin would inherit from. 这是插件将继承的类。

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

"PluginPlumbing.h". “PluginPlumbing.h”。 The class that contains the plumbing. 包含管道的类。

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

The outer framework code would (by loading the DLL/so of the plugin) acquire a pointer to a PluginPlumbing class instance, and then call PlumbingFunction() on it. 外部框架代码将(通过加载插件的DLL / so)获取指向PluginPlumbing类实例的指针,然后在其上调用PlumbingFunction()。

However, the conundrum I have is, I can't just upcast a PluginBase pointer I get from the DLL/so to a PluginPlumbing pointer as it clearly doesn't actually inherit from PluginPlumbing. 但是,我面临的难题是,我不能只是将从DLL / so中获得的PluginBase指针上载到PluginPlumbing指针,因为它显然实际上并不继承自PluginPlumbing。 And I can't have the plugin inherit from PluginPlumbing, because then I'm back at square one of exposing the plumbing to the plugin writer. 而且我不能让插件从PluginPlumbing继承,因为那时我回到了将管道暴露给插件编写者的地方。

The only solution I can imagine is that instead of nicely inheriting, the PluginBase and the PluginPlumbing are entirely separate classes. 我能想象的唯一解决方案是,PluginBase和PluginPlumbing不是很好的继承,而是完全独立的类。 The PluginBase would be instantiated by the DLL/so, and the PluginPlumbing instance would be instantiated by the framework, and handed that PluginBase pointer so it can make the plumbing calls. PluginBase将由DLL / so实例化,而PluginPlumbing实例将由框架实例化,并将该PluginBase指针传递给它,以便它可以进行管道调用。 Is that the only solution to go about it? 那是唯一的解决方案吗?

If you want to expose some functionality from your plugins to external software you definitely have to provide some interface for that. 如果要将插件的某些功能公开给外部软件,则必须为此提供一些接口。

In your example you provided PluginBase interface with PluginProcess() function, so, any other user of your PluginBase interface can call it without having to care about its implementation. 在您的示例中,您为PluginBase接口提供了PluginProcess()函数,因此,您的PluginBase接口的任何其他用户都可以调用它,而无需关心其实现。

If you need another interface with another method - do it the same way. 如果您需要使用其他方法的另一个接口-请以相同的方式进行。

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

And hide the implementation in your DLL implementation: 并将实现隐藏在DLL实现中:

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

If it needs additional parameters - also pass it as abstract interface classes or POD structures. 如果它需要其他参数-还将其作为抽象接口类或POD结构传递。 You should also have some declaration for your plugin function which will create exact instances for your interface implementations (which should be accessible by users of your plugins). 您还应该为插件函数声明一些内容,这些声明将为您的接口实现创建确切的实例(插件的用户应该可以访问它们)。

To summarize this, you should have something like that: 总结一下,您应该具有以下内容:

// 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();
}

And users of your plugin can use it only by including myplugininterface.h and obtaining addresses of create functions (this is platform dependent). 并且您插件的用户只能通过包含myplugininterface.h并获取create函数的地址(这取决于平台)来使用它。

Keep in mind, that if you return instances created by new and allow users of your plugins to delete objects created like that - you must declare virtual destructor for your interface classes. 请记住,如果返回由new创建的实例,并允许插件的用户delete创建的对象,则必须为接口类声明虚拟析构函数。

This is a general approach. 这是一种通用方法。 It has some pitfalls when you have hierarchy for your plugin objects, you cant share common implementation for your abstract classes without putting some additional effort (assuming you don't want to have copypasta) 当您具有插件对象的层次结构时,它会有一些陷阱,您不能不付出额外的努力就无法共享抽象类的通用实现(假设您不想拥有copypasta)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM