簡體   English   中英

我可以從構造函數中傳遞成員函數指針嗎?

[英]Can I pass a member function pointer from within a constructor?

知道事情是如何在這里發生的,有人會立即標記這個“騙子”,但我肯定找不到“構造函數傳遞成員函數”的好例子。 大量傳遞給構造函數或在外部傳遞成員函數,但不是從構造函數內部傳遞......

故事:我們正在使用一個使用“郵箱”的庫,並為 RX 中斷回調提供了一個鈎子。 我們有自己的設備類。 每個對象實例都需要能夠處理庫郵箱之一。 因此構造函數接受一個郵箱(將來可能> 1),然后將自己注冊到 comms 庫。

簡單地說:我希望每個對象構造函數都將指向它的“處理程序”成員函數的指針傳遞給這個庫。

問題當然是成員函數與標准函數指針。 標准函數指針工作正常,靜態類函數“工作”,但我們需要使用局部對象變量而不是靜態類變量。

我已經閱讀了一百萬個線程,並看到了帶有隱藏“this”參數的成員函數與標准 C 函數指針等之間的問題。

曾嘗試使用 lambda 和 std::function<> 方法......也許我正在與不可能的事情作斗爭? 在構造函數完成創建實例之前,是否不可能將指針傳遞給函數?

示例...(還有一個用於代碼重用目的的類層次結構,子類中會有一些函數覆蓋和擴展,但基本的郵箱設置應該在頂級基類中)


class Base // Object that processes received communication frames
{
public: 
    Base(int);
    bool Initialized;
protected:
    fooframestruct rxframe;
    bool newframe;
    void Handler(const fooframestruct&);
    void DoOtherStuff();
};

Base::Base(int rxmailbox) : 
    Initialized(false),
    newframe(false)
{
    // point comms library to instance function when data received by its mailbox
    somelibraryobject.OnReceive(rxmailbox, this->Handler);  // obviously doesn't work cuz member func
}

void Base::Handler(const fooframestruct &thisframe)
{
    // callback function - just grab the frame and set a flag
    rxframe = thisframe;
    newframe = true;
}

void Base::DoOtherStuff()
{
    cout << "blah";
    Initialized = true;
}

class SubClass : Base
{
public:
    using Base:Base;
    void ExtendWithOtherStuff();
}   


main 
{

Base device1 = new Base(1);
Base device2 = new Base(7);
SubClass device3 = new Base(5);

// etc. 

}

自然編譯器失敗,非靜態成員函數的無效使用,如上所述,我完全理解為什么,只是不是最好的方法是什么。

我意識到我可以做一些事情,比如創建一個二級類函數說

Base.RegisterMB() 

然后在主設置中調用它,例如:

Base device1 = new Base(1);
device1.RegisterMB();

但我討厭“兩步對象初始化”。 我想第三個解決方法是在類之外設置庫,也就是......

somelibraryobject.OnReceive(rxmailbox, device1.Handler); 

或者至少是類似的東西,但同樣,如果可能的話,我寧願封裝對象設置。

但也許我不能?

成員函數需要調用對象的實例。 雖然標准組件提供了這樣做的方法,但沒有一個會導致函數指針的產生。

在這種特殊情況下,您只能將地址返回給靜態或全局函數,或無捕獲的 lambda。如果您必須“捕獲”對象的狀態,則您自己設計了這種機制。 例如,您可能擁有 factory\\pool\\manager,它可以允許基於某個參數查詢現有對象,在參數中傳遞指針(訪問者模式?)等等。

問題的答案是:不。

  1. 創建一個只注冊一次的靜態函數。
  2. 在您的類中創建一個靜態列表,用於注冊該列表中的每個實例。 讓它在每個實例銷毀時取消注冊該實例。
  3. 當該靜態函數被調用時,讓它使用相關函數調用每個實例。

最壞的情況是你沒有實例,靜態函數被調用而無關緊要。

你能讓somelibraryobject.OnReceive()接受你的回調例程作為std::function嗎?

如果是這樣,您可以使用捕獲 lambda 來捕獲this ,如下所示:

somelibraryobject.OnReceive (rxmailbox, [this] mutable () { this->Handler (); });

現場演示

如果Handler()被聲明為const ,那么你就不需要mutable

基本上答案是:NO 不能在構造函數內部執行此操作,而且在構造函數外部執行此操作非常痛苦,導致 C++-fighting-with-C 痛苦,從而導致丑陋的臃腫不可讀的愚蠢代碼。

在構造函數之外,在主對象設置中,我還嘗試了此處概述的 std::bind 方法: https : //embeddedartistry.com/blog/2017/1/26/c11-improving-your-callback-game

Client c;
register_callback(std::bind(&Client::func, &c, std::placeholders::_1));

(我應該指出 - 正如 Zaiborg 從一開始所建議的那樣)但那里也沒有愛。 沒有重載函數的實例與參數列表匹配。

這里的痛苦多於價值......我將放棄使用中斷驅動邏輯的能力,不得不一直笨拙地輪詢消息。

暫無
暫無

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

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