簡體   English   中英

C ++插件系統,其中插件從基類繼承

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

我正在嘗試向我的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 / so)獲取指向PluginPlumbing類實例的指針,然后在其上調用PlumbingFunction()。

但是,我面臨的難題是,我不能只是將從DLL / so中獲得的PluginBase指針上載到PluginPlumbing指針,因為它顯然實際上並不繼承自PluginPlumbing。 而且我不能讓插件從PluginPlumbing繼承,因為那時我回到了將管道暴露給插件編寫者的地方。

我能想象的唯一解決方案是,PluginBase和PluginPlumbing不是很好的繼承,而是完全獨立的類。 PluginBase將由DLL / so實例化,而PluginPlumbing實例將由框架實例化,並將該PluginBase指針傳遞給它,以便它可以進行管道調用。 那是唯一的解決方案嗎?

如果要將插件的某些功能公開給外部軟件,則必須為此提供一些接口。

在您的示例中,您為PluginBase接口提供了PluginProcess()函數,因此,您的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)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM