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

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

明確一點即回調函數須要是靜態函數。緣由:編程

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

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

解決方法

  • 使用static修飾成員函數。static不含this指針。
  • 不用static修飾的成員函數,須要藉助中間變量來訪問。這個演示的很好。
  • 也能夠在回調函數中增長一個變量,類型爲該類的類型,做爲this指針的傳遞。

下面講解一下第二點,我認爲比較好用。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)();
}

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

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

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

(a.*ptrnonstatic)();

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

若是在咱們的編程過程當中:code

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

咱們可使用:blog

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

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

而後調用的時候咱們能夠:作用域

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

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

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

其它

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

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

代入便可。

相關文章
相關標籤/搜索