C++回調函數、靜態函數、成員函數踩過的坑。


C++回調函數、靜態函數、成員函數踩過的坑。

明確一點即回調函數需要是靜態函數。原因:

  • 普通的C++成員函數都隱含了一個this指針作為參數,這樣使得回調函數的參數和成員函數參數個數不匹配。

若不想使用C式函數作為回調函數呢?(破壞封裝性)

解決方法

  • 使用static修飾成員函數。static不含this指針。
  • 不用static修飾的成員函數,需要借助中間變量來訪問。這個演示的很好。
  • 也可以在回調函數中增加一個變量,類型為該類的類型,作為this指針的傳遞。

下面講解一下第二點,我認為比較好用。

class A 
{
public:
    static void staticmember(){cout<<"static"<<endl;}   //static member
    void nonstatic(){cout<<"nonstatic"<<endl;}          //nonstatic member
    virtual void virtualmember(){cout<<"virtual"<<endl;};//virtual member
};
int main()
{
    A a;
    //static成員函數,取得的是該函數在內存中的實際地址,而且因為static成員是全局的,所以不能用A::限定符
    void (*ptrstatic)() = &A::staticmember;      
    //nonstatic成員函數 取得的是該函數在內存中的實際地址     
    void (A::*ptrnonstatic)() = &A::nonstatic;
    //虛函數取得的是虛函數表中的偏移值,這樣可以保證能過指針調用時同樣的多態效果
    void (A::*ptrvirtual)() = &A::virtualmember;
    //函數指針的使用方式
    ptrstatic();
    (a.*ptrnonstatic)();
    (a.*ptrvirtual)();
}

直接用類名引出非靜態成員函數,賦值給函數指針:

//nonstatic成員函數 取得的是該函數在內存中的實際地址     
void (A::*ptrnonstatic)() = &A::nonstatic;

隨后需要運行回調函數的時候,使用一個輔助變量來運行,格式為:(變量名. * 函數指針)(參數)

(a.*ptrnonstatic)();

應用:類中成員函數的函數指針寫法

如果在我們的編程過程中:

  1. 需要使用到回調函數。
  2. 回調函數是一個類的成員函數。
  3. 此成員函數不是靜態函數,也不適合做靜態函數。

我們可以使用:

bool (DoTask::*function)(void *arg);

其中DoTask是一個類名,上面寫的就是一個返回值為bool類型,參數為void *類型的函數指針,指向DoTask這個類中的成員函數。

然后調用的時候我們可以:

Dotask d;
//注意ReadData函數不用加括號,要加作用域和地址符
bool (DoTask::*function)(void *arg) = &DoTask::ReadData;
(d.*function)(NULL);

注意點就是賦值給函數指針的時候需要取地址符、加作用域、函數不加括號,直接函數名即可。

調用的時候,用一個實例去調用函數指針即可。

其它

假如我們將函數指針放在一個結構體中:

struct task
{
    bool (DoTask::*function)(void *arg);
    void *arg;
};

那么我們調用它的時候也是一樣的。

struct task t;
t.function = &DoTask::ReadData;
...
DoTask d;
(d.*(t.function))(NULL);    //完成調用。

現在看調用這一步。參照上面的:

(d.*function)(NULL)

只不過function現在存在結構體中,替換成從結構體中取出來即可:

function 替換成 t.function

代入即可。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM