2017-03-15 35 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的對象 - 你必須 聲明虛析構函數爲您的接口類。

這是一種常規方法。它有一些缺陷,當你有插件對象的層次爲 時,你不能分享你的抽象 類的通用實現,而不需要付出額外的努力(假設你不想有副本)