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

代入即可。

posted @ 2019-01-15 14:21  _NewMan  阅读(4408)  评论(0编辑  收藏  举报