2017-03-15 33 views
0

我想为我的C++代码库添加插件功能。困难的产生是因为插件需要包含插件作者不应该知道的管道(因此保持包含文件简单)。 所以,这是设置:插件继承基类的C++插件系统

“PluginBase.h”。这是插件将继承的类。

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

“PluginPlumbing.h”。包含管道的类。

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

外框架代码将(通过装载DLL /所以插件的)获得一个指向PluginPlumbing类实例,然后调用PlumbingFunction()就可以了。然而,我所遇到的难题是,我不能只是将从DLL /所得到的PluginBase指针上传到PluginPlumbing指针,因为它显然实际上并不从PluginPlumbing继承。而且我不能让Plugin从PluginPlumbing继承,因为那时我就回到了插件编写者身上。

我可以想象唯一的解决办法是,代替很好地继承,所述PluginBase和PluginPlumbing是完全单独的类。 PluginBase将由DLL/so实例化,并且PluginPlumbing实例将由框架实例化,并递交该PluginBase指针,以便它可以进行管道调用。这是唯一的解决方案吗?

回答

0

如果你想从你的插件到外部软件揭露一些功能,你一定要提供一些接口。

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

如果需要使用其他方法的另一个接口 - 做同样的方式。

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的对象 - 你必须 声明虚析构函数为您的接口类。

这是一种常规方法。它有一些缺陷,当你有插件对象的层次为 时,你不能分享你的抽象 类的通用实现,而不需要付出额外的努力(假设你不想有副本)