您的位置:首页 > 编程语言 > C语言/C++

玩弄C++:回调一个类成员函数

2016-01-25 16:38 519 查看
原文:http://www.cnblogs.com/cason/archive/2012/06/16/2552031.html

回调函数在C语言中用的非常频繁,它可以作用于结构体,但是到了C++中,类的成员函数是不能作为回调函数的。
详细说来,C的结构体中的函数都是函数指针,调用的时候一般不操作结构体内的数据否则要显式地在调用时传入
结构体的数据,即C中没有this这个概念。到了C++,假设类成员函数可以作为回调函数,那么这个函数对类成员
变量的操作作用于哪个实例呢?这显然是无法确定的,只有主动告知之。
关于this指针:看过C++类汇编代码的同志们都知道,在类实例调用它的成员函数时,call之前一定会有一步
  mov ecx, [ebp-xxx]
这个指令就是根据栈基址找到改实例在栈中的地址,并放入ecx中;在被调用的函数中,所有对类成员变量的操作
都是根据这个ecx带进来的地址完成的。因此,这就是类的成员函数不能作为回调函数的根本原因,那我们给他个
ecx不就行了嘛~

#include <stdio.h>

#include <stdlib.h>

#include <stdarg.h>

template </*return value*/typename RETYPE>

class Function{

public:

Function(){

this->objaddr = 0;

this->callback = 0;

}

Function(int *objAddr, void *cb){

objaddr = (int)objAddr;

callback = cb;

}

Function(Function &input){

this->objaddr = input.objaddr;

this->callback = input.callback;

}

static RETYPE call(int addr, void *callback, int n){

__asm{MOV ECX, addr}

return ((int (__stdcall *)(int)) callback)(n);

}

//need to be extended

static Function bind(void *objAddr, ...){

va_list stack;

va_start(stack, objAddr);

Function ret((int *)objAddr, \

(void *)va_arg(stack, int));

return ret;

}

RETYPE operator()(int n){

int addr = objaddr;

void *cb = callback;

return call(addr, cb, n);

}

private:

int objaddr;

void *callback;

};

class A{

private:

Function<int> cb;

public:

A(Function<int> callback)

:cb(callback)

{}

void t(int n){

cb(n);

}

};

class B{

public:

int tt;

B():tt(0){

printf("B::tt inited as 0\n");

}

//private:

int t(int n){

tt += n;

printf("B::tt changed to %d!\n", tt);

return tt;

}

};

int main(){

B b1, b2;

A a(Function<int>::bind(&b1, B::t));

a.t(2);

a.t(3);

Function<int> fx;

fx = Function<int>::bind(&b2, B::t);

fx(9);

return 0;

}

我定义了一个模板Function,它的作用有三点:
1、把类成员函数的地址取出来,并转换成void *类型(通过进出栈来退化thiscall约定);见 bind;
2、保存该回调函数作用的实例地址;
3、提供调用该回调函数的方式(转换成stdcall,之前没有注意这点而被默认的cdecl搞得莫名其妙,因为它没有自动清栈);见 call。
使用这个模板的方法很简单,它就是一个变量而已~
记得跟我培训的C++大神说过,类成员函数是不能作为线程被创建的,原因应该也是这个;当然,用这个模板的话迂回一下也是可以实现的。



阅读(439) | 评论(0) | 转发(1) |

0
上一篇:如何将一个模板类A作为模板类B的模板参数

下一篇:WinRar命令行参数

相关热门文章

欢迎letitbe413在ChinaUnix博...

欢迎linminchao在ChinaUnix博...

欢迎sagatagintoki在ChinaUnix...

欢迎abc16156在ChinaUnix博客...

欢迎yuliangguiguzi在ChinaUni...

test123

编写安全代码——小心有符号数...

使用openssl api进行加密解密...

一段自己打印自己的c程序...

sql relay的c++接口

linux dhcp peizhi roc

关于Unix文件的软链接

求教这个命令什么意思,我是新...

sed -e "/grep/d" 是什么意思...

谁能够帮我解决LINUX 2.6 10...

给主人留下些什么吧!~~

评论热议
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: