0228 C C++ callback  memberfunc info

网上资料倒是不少:
c++的class有一个隐含的this, 所以的调用其实都是通过this进行的, 比如:
引用:
class Foo
&leftsign;
public:
void func() &leftsign;m_int = 0;&rightsign;
private:
int m_int;
&rightsign;
 

其实func()里面发生的是this->m_int = 0; 就是说class会自动添加这个this. 而thread里面的函数, 其实是按系统的call back方式调用的, 纯c的方式, 不会添加这个this, 这样在函数传递是堆栈里面就没有传递this, 所以这个函数指针就是无效的. 为了防止这种行为, c++的编译器都检测并禁止这种行为.

非成员函数没有this, static 成员函数不接收this, 所以是两种可以被接受的方式.

子线程函数可以是成员函数,要求就是成员函数是static的。之所以有这样的要求,是因为类的成员函数(除了static的),都默认有个this参数用来访问对象的内部成员函数和变量,虽然这个参数没有显示出来,但是编译器会自动添加。这样最后生成的 成员函数是不可能满足_beginthread或者CreateThread以及其他一些api函数(例如需要回调函数的API)的要求的,因为这些API的参数是不会接受一个有this指针参数的函数的。
static函数没有this指针参数,所以可以用来作为线程或者回调函数。但是static函数不能访问类的非static成员。要解决这个问题,一个简单的做法是把this指针作为参数在创建线程的时候传给线程函数,线程函数里面把这个指针cast成 类的指针,通过这个指针就可以访问类的成员了。

问题是 我又不能添加参数,这都是定义死了的~~~~~~~

不定义类成员函数为线程函数,而将线程函数定义为类的友元函数。这样,线程函数也可以有类成员函数同等的权限;

实际上也还是要传一个THIS指针

回调函数和成员函数
 
许多程序员都发现,利用MFC或者其它的C++应用编写回调函数是非常麻烦的,其根本原因是回调函数是基于C编程的Windows SDK的技术,不是针对C++的,程序员可以将一个C函数直接作为回调函数,但是如果试图直接使用C++的成员函数作为回调函数将发生错误,甚至编译就不能通过。通过查询资料发现,其错误是普通的C++成员函数都隐含了一个传递函数作为参数,亦即“this”指针,C++通过传递一个指向自身的指针给其成员函数从而实现程序函数可以访问C++的数据成员。这也可以理解为什么C++类的多个实例可以共享成员函数但是确有不同的数据成员。由于this指针的作用,使得将一个CALLBACK型的成员函数作为回调函数安装时就会因为隐含的this指针使得函数参数个数不匹配,从而导致回调函数安装失败。要解决这一问题的关键就是不让this指针起作用,通过采用以下两种典型技术可以解决在C++中使用回调函数所遇到的问题。这种方法具有通用性,适合于任何C++。   

1). 不使用成员函数,直接使用普通C函数,为了实现在C函数中可以访问类的成员变量,可以使用友元操作符(friend),在C++中将该C函数说明为类的友元即可。这种处理机制与普通的C编程中使用回调函数一样。   

2). 使用静态成员函数,静态成员函数不使用this指针作为隐含参数,这样就可以作为回调函数了。静态成员函数具有两大特点:其一,可以在没有类实例的情况下使用;其二,只能访问静态成员变量和静态成员函数,不能访问非静态成员变量和非静态成员函数。由于在C++中使用类成员函数作为回调函数的目的就是为了访问所有的成员变量和成员函数,如果作不到这一点将不具有实际意义。解决的办法也很简单,就是使用一个静态类指针作为类成员,通过在类创建时初始化该静态指针,如pThis=this,然后在回调函数中通过该静态指针就可以访问所有成员变量和成员函数了。这种处理办法适用于只有一个类实例的情况,因为多个类实例将共享静态类成员和静态成员函数,这就导致静态指针指向最后创建的类实例。为了避免这种情况,可以使用回调函数的一个参数来传递this指针,从而实现数据成员共享。这种方法稍稍麻烦,这里就不再赘述。

实现不需要辅助函数实现回调非静态类成员函数 
#define CLASS_MEMBER_FUNCTION_SUPPORT_CALLBACK( ThisPointerAddress ) \\
 __asm mov eax , (ThisPointerAddress)\\
 __asm mov [ebp-4] , eax

只是需要一个变通的方法,可以把对象指针传入该静态成员函数,一个方法是通过某个参数的形式,把this指针传入,通过该指针调用普通成员变量和函数,还有一个方法是在类里建立一个静态成员变量
class   CMyClass
&leftsign;
private:
    static   CMyClass*   m_pThis;

&rightsign;;

每次调用需要callback函数之前把该变量设为this(注意,比较危险,除非你可以肯定程序始终只有一个线程可以调用该callback函数),然后静态函数内部即可通过m_pThis访问普通成员变量和函数

利用一组宏定义实现类成员函数的回调
实现类成员函数的回调,已有方法有例如MFC的CCmdTarget类采用一组枚举来区分参数和返回值,然后用一组数组来存储对象和指针;以及使用模板来实现回调。本文讨论一种通过宏定义实现类成员函数的回调的方法。

实现它需要两个先决条件:
1.回调函数所属的类需要从已知的类继承,最好有相同的基类。例如CObject。
2.回调函数必须是public的类成员函数,不能是私有、保护或者静态的成员函数。

C++消息连接的一种系统方法
用过C++进行过面向对象程序设计的用户都知道,程序中的对象很少单独存在。不考虑对象间的相互作用几乎是不可能的。所以,标识对象间的关系或建立对象间的消息连接是面向对象程序设计的一项重要任务。本文着重从C++程序设计的角度,提出一种建立对象间消息连接的实用方法。如果你想详细了解面向对象程序设计技术,请参阅有关专著。大家都知道对象是数据和方法的封装体。在C++中,它们分别表现为数据成员和成员函数。程序设计者通过执行对象的各种方法,来改变对象的状态(即改变对象的属性数据)。从而使该对象发生某些“事件”。当一对象发生某事件时,它通常需向其它相关对象发送“消息”,请求它们作出一些处理。 这时,发生事件并向其它对象请求处理的对象被称为“事件对象”,而处理事件的对象被称为“回调对象”。回调对象对事件的处理称为“回调函数”。在C++中,这一过程相当于:当事件对象发生事件时,调用回调对象的某些成员函数。通常的作法是回调对象向事件对象传递对象指针。但这种方法不通用。为了减少程序设计的工作量,本文提出一种建立对象间消息连接的系统方法。它的思路是:将“事件发生→请求处理→执行处理”这一过程抽象成一个“回调”(CallBack)类。通过继承,用户可以轻松获取建立对象间消息连接的机制。

历史博文

标签:, , , ,
六月 22, 2006 at 4:33 下午 by yippee 1,017 次
Category: Dev
Tags: , , , ,