簡體   English   中英

以后如何存儲調用不同類的成員函數,繼承自同一個接口類

[英]How to store and invoke later, the member functions of different classes, which are inherited from the same interface class

我正在創建一個應用程序,它可以通過從接口類(稱為 AppInterface)繼承並由 Qt 的插件加載器系統加載的幾個插件進行擴展,目前。 被視為核心的類的全局靜態實例可用於每個插件,使用 dll。

現在,為了在插件之間交換數據,我計划在核心中創建 2 個函數,一個將偵聽器函數指針存儲在映射中的鍵下,另一個用於調用鍵下存儲的函數,使用對他們的爭論。

std::map<char*,std::list<void*> > listenerMap;
template<typename... Args, typename T>
void listen(char* key,  T *inst, void (T::*listenerSlot)(Args...))
{
get the functor list with key from the listener map and append the functor.
}
template<typename ...Args> 
void broadcast (char* key, Args... args)
{
get the list with key from the listener map and invoke all the functors with the given arguments.
}

我還沒有找到將函子與其類對象一起存儲並稍后調用它們的方法。 函子參數不是固定的,它們會因函數而異,除非它們在偵聽器映射中位於相同的鍵下。

廣播和監聽函數的結構有什么變化,或者調用存儲的成員函數的更好想法?

或者我可以使用每個插件都繼承的 AppInterface 嗎?

注意:我決定不使用 Qt 信號槽系統,因為我希望 AppInterface 成為基類而不是 QObject,原因有幾個。

似乎您想依靠 name 來知道要傳遞哪個參數,因此插件應該知道其他插件如何命名它們的方法以及要傳遞哪個參數...

那么提供一種檢索插件的方法似乎更簡單:

AppInterface* GetPlugin(const char* name);

dynamic_cast插件將動態dynamic_cast為想要的並直接調用其上的任何方法。 例如:

struct SomePlugin : AppInterface
{
    // ...
    void print();
    int foo(int n);
};

struct MyPlugin : AppInterface
{
    // ...
    void bar() {
        auto* plugin = dynamic_cast<SomePlugIn>(GetPlugin("SomePlugIn"));

        if (plugin) {
             plugin->print();
             int n = plugin->foo(42);
             // ...
        }
    }
};

使用一些約定作為static const char* Plugin::Name ,您可以直接在函數中提供 dynamic_cast :

template <typename Plugin>
Plugin* GetPlugin() { return dynamic_cast<Plugin>(GetPlugin(Plugin::Name)); }

如果你真的想保留你的接口來注冊函數並調用它們,你可以使用std::any :/

std::map<std::string, std::any> listenerMap;

template<typename Sig>
void register(const char* key, std::function<Sig> f);
{
    listenerMap[key] = f;
}

template<typename Sig, typename ...Args> 
void broadcast(const char* key, Args&& ... args)
{
     auto it = listenerMap.find(key);
     if (it != listenerMap.end()) {
         auto* f = std::any_cast<std::function<Sig>>(&it->second);
         if (f) {
              (*f)(std::forward<Args>(args)...);
         }
     }
}

用法類似於:

struct MyPlugin : AppInterface
{
    // ...
    void print() const;
    void foo(int) const;

    void my_register() {
         register<void()>("my_print", [this](){ this->print(); });
         register<void(int)>("foo", [this](int n){ this->foo(n); });
    }

    void call_me() {
        broadcast<void()>("my_print");
        broadcast<void(int)>("foo", 42);
    }

};

為了安全起見,您應該通過Sig進行broadcast而不是從Args扣除。 傳遞std::string&而不是const std::string&const char*而不是std::string會使預期的std::function<void(const std::string&)>更改為std::function<void(std::string&)>std::any_cast會失敗。

暫無
暫無

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

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