clq

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

http://topic.csdn.net/u/20101021/10/af09d7fb-5ab3-403d-a364-a6f06f472968.html

比如成员函数模板必须是:

template<typename T, typename RT, typename P1>
void test(T t1, RT (T::*mem_fun)(P1) , P1 p);


而函数指针即能能是:
template<typename RT, typename P>
void test(RT (*func)(P) , P p);

又能是:
template<typename F, typename P>
void test (F fun, P p)


根据使用场景,可以选择简单的定义。

--------------------------------------------------

http://blog.sina.com.cn/s/blog_4a50d85b0100umqe.html

C语言的指针相当的灵活方便,但也相当容易出错。许多C语言初学者,甚至C语言老鸟都很容易栽倒在C语言的指针下。但不可否认的是,指针在C语言中的位置极其重要,也许可以偏激一点的来说:没有指针的C程序不是真正的C程序。
  然而C++的指针却常常给我一种束手束脚的感觉。C++比C语言有更严格的静态类型,更加强调类型安全,强调编译时检查。因此,对于C语言中最容易错 用的指针,更是不能放过:C++的指针被分成数据指针,数据成员指针,函数指针,成员函数指针,而且不能随便相互转换。而且这些指针的声明格式都不一样:

数据指针 T *
成员数据指针 T::*
函数指针 R (*)(...)
成员函数指针 R (T::*)(...)

还有一个更重要的区别是,指针所占的空间也不一样了。即使在32位系统中,所占的空间也有可能是4字节、8字节、12字节甚至16字节,这个依据平台及编译器,有很大的变化。
  尽管C++中仍然有万能指针void*,但它却属于被批斗的对象,而且再也不能“万能”了。它不能转换成成员指针。

  这样一来,C++的指针就变得很尴尬:我们需要一种指针能够指向同一类型的数据,不管这个数据是普通数据,还是成员数据;我们更需要一种指针能够指向同一类型的函数,不管这个函数是静态函数,还是成员函数。但是没有,至少从现在的C++标准中,还没有看到。
 
沐枫网志 C++指针探讨(三)成员函数指针

  自从有了类,我们开始按照 数据+操作 的方式来组织数据结构;自从有了模板,我们又开始把 数据 和 算法 分离,以便重用,实在够折腾人的。但不管怎么折腾,现在大多数函数都不再单身,都嫁给了类,进了围城。可是我们仍然需要能够自由调用这些成员函数。
  考虑一下windows下的定时调用。SetTimer函数的原型是这样的:

C++指针探讨 <wbr>(三) <wbr>成员函数指针UINT_PTR SetTimer(
C++指针探讨 <wbr>(三) <wbr>成员函数指针    HWND hWnd,
C++指针探讨 <wbr>(三) <wbr>成员函数指针    UINT_PTR nIDEvent,
C++指针探讨 <wbr>(三) <wbr>成员函数指针    UINT uElapse,
C++指针探讨 <wbr>(三) <wbr>成员函数指针    TIMERPROC lpTimerFunc
C++指针探讨 <wbr>(三) <wbr>成员函数指针);
C++指针探讨 <wbr>(三) <wbr>成员函数指针

其中,参数就不解释了,这个函数估计大多数windows开发人员都知道。lpTimerFunc是个会被定时调用的函数指针。假如我们不通过 WM_TIMER消息来触发定时器,而是通过lpTimerFunc来定时工作,那么我们就只能使用普通函数或静态函数,而无论如何都不能使用成员函数, 哪怕通过静态函数转调也不行。

  再考虑一下线程的创建:

C++指针探讨 <wbr>(三) <wbr>成员函数指针uintptr_t _beginthread( 
C++指针探讨 <wbr>(三) <wbr>成员函数指针   
void*start_address )( void * ),
C++指针探讨 <wbr>(三) <wbr>成员函数指针   unsigned stack_size,
C++指针探讨 <wbr>(三) <wbr>成员函数指针   
void *arglist 
C++指针探讨 <wbr>(三) <wbr>成员函数指针);C++指针探讨 <wbr>(三) <wbr>成员函数指针

start_address仍然只支持普通函数。不过这回好了,它允许回调函数一个void*参数,它将会arglist作为参数来调用 start_address。于是,聪明的C++程序员,就利用arglist传递this指针,从而利用静态函数成功的调用到了成员函数了:

C++指针探讨 <wbr>(三) <wbr>成员函数指针class mythread
C++指针探讨 <wbr>(三) <wbr>成员函数指针
{
C++指针探讨 <wbr>(三) <wbr>成员函数指针  
public:
C++指针探讨 <wbr>(三) <wbr>成员函数指针    
static void doit(void* pThis)
C++指针探讨 <wbr>(三) <wbr>成员函数指针    
{
C++指针探讨 <wbr>(三) <wbr>成员函数指针    ((mythread*)pThis)
->doit();
C++指针探讨 <wbr>(三) <wbr>成员函数指针    }

C++指针探讨 <wbr>(三) <wbr>成员函数指针    
void doit(){C++指针探讨 <wbr>(三) <wbr>成员函数指针}
C++指针探讨 <wbr>(三) <wbr>成员函数指针}
;
C++指针探讨 <wbr>(三) <wbr>成员函数指针
C++指针探讨 <wbr>(三) <wbr>成员函数指针main()
C++指针探讨 <wbr>(三) <wbr>成员函数指针
{
C++指针探讨 <wbr>(三) <wbr>成员函数指针  C++指针探讨 <wbr>(三) <wbr>成员函数指针
C++指针探讨 <wbr>(三) <wbr>成员函数指针  mythread
* pmt = new mythread;
C++指针探讨 <wbr>(三) <wbr>成员函数指针  _beginthread(
&mythread::doit, 0, (void*)pmt);
C++指针探讨 <wbr>(三) <wbr>成员函数指针  C++指针探讨 <wbr>(三) <wbr>成员函数指针
C++指针探讨 <wbr>(三) <wbr>成员函数指针}

  但是显然,C++程序员肯定不会因此而满足。这里头有许多被C++批判的不安定因素。它使用了C++中被认为不安全的类型转换,不安全的void*指 针,等等等等。但这是系统为C语言留下的调用接口,这也就认了。那么假如,我们就在C++程序中如何来调用成员函数指针呢?
  如下例,我们打算对vector中的所有类调用其指定的成员函数:

C++指针探讨 <wbr>(三) <wbr>成员函数指针#include <vector>
C++指针探讨 <wbr>(三) <wbr>成员函数指针#include 
<algorithm>
C++指针探讨 <wbr>(三) <wbr>成员函数指针#include 
<functional>
C++指针探讨 <wbr>(三) <wbr>成员函数指针#include 
<iostream>
C++指针探讨 <wbr>(三) <wbr>成员函数指针
using namespace std;
C++指针探讨 <wbr>(三) <wbr>成员函数指针
C++指针探讨 <wbr>(三) <wbr>成员函数指针
class A
C++指针探讨 <wbr>(三) <wbr>成员函数指针
{
C++指针探讨 <wbr>(三) <wbr>成员函数指针    
int value;
C++指针探讨 <wbr>(三) <wbr>成员函数指针
public:
C++指针探讨 <wbr>(三) <wbr>成员函数指针    A(
int v){value = v;}
C++指针探讨 <wbr>(三) <wbr>成员函数指针    
void doit(){ cout << value << endl;};
C++指针探讨 <wbr>(三) <wbr>成员函数指针    
static void call_doit(A& rThis)
C++指针探讨 <wbr>(三) <wbr>成员函数指针    
{
C++指针探讨 <wbr>(三) <wbr>成员函数指针        rThis.doit();
C++指针探讨 <wbr>(三) <wbr>成员函数指针    }

C++指针探讨 <wbr>(三) <wbr>成员函数指针}
;
C++指针探讨 <wbr>(三) <wbr>成员函数指针
C++指针探讨 <wbr>(三) <wbr>成员函数指针
C++指针探讨 <wbr>(三) <wbr>成员函数指针
int main()
C++指针探讨 <wbr>(三) <wbr>成员函数指针
{
C++指针探讨 <wbr>(三) <wbr>成员函数指针    vector
<A> va;
C++指针探讨 <wbr>(三) <wbr>成员函数指针    va.push_back(A(
1));
C++指针探讨 <wbr>(三) <wbr>成员函数指针    va.push_back(A(
2));
C++指针探讨 <wbr>(三) <wbr>成员函数指针    va.push_back(A(
3));
C++指针探讨 <wbr>(三) <wbr>成员函数指针    va.push_back(A(
4));
C++指针探讨 <wbr>(三) <wbr>成员函数指针    
//方法1:
C++指针探讨 <wbr>(三) <wbr>成员函数指针    
//for_each(va.begin(), va.end(), &A::doit); //error
C++指针探讨 <wbr>(三) <wbr>成员函数指针    
//方法2:
C++指针探讨 <wbr>(三) <wbr>成员函数指针
    for_each(va.begin(), va.end(), &A::call_doit);
C++指针探讨 <wbr>(三) <wbr>成员函数指针    
//方法3:
C++指针探讨 <wbr>(三) <wbr>成员函数指针
    for_each(va.begin(), va.end(), mem_fun_ref<void, A>(&A::doit));
C++指针探讨 <wbr>(三) <wbr>成员函数指针
C++指针探讨 <wbr>(三) <wbr>成员函数指针    system(
"Pause");
C++指针探讨 <wbr>(三) <wbr>成员函数指针
C++指针探讨 <wbr>(三) <wbr>成员函数指针    
return 0;
C++指针探讨 <wbr>(三) <wbr>成员函数指针}

C++指针探讨 <wbr>(三) <wbr>成员函数指针

  方法1,编译不能通过。for_each只允许具有一个参数的函数指针或函数对象,哪怕A::doit默认有一个this指针参数也不行。不是for_each没考虑到这一点,而是根本做不到!
  方法2,显然是受到了beginthread的启发,使用一个静态函数来转调用,哈哈成功了。但是不爽!这不是C++。
  方法3,呼,好不容易啊,终于用mem_fun_ref包装成功了成员函数指针。
  似乎方法3不错,又是类型安全的,又可以通用--慢着,首先,它很丑,哪有调用普通C函数指针那么漂亮啊(见方法2),用了一大串包装,又是尖括号又 是圆括号,还少不了&号!其次,它只能包装不超过一个参数的函数!尽管它在for_each中够用了,但是你要是想用在超过一个参数的场合,那只 有一句话:不可能的任务。

  是的,在标准C++中,这是不可能的任务。但事情并不总是悲观的,至少有许多第三方库提供了超越mem_fun的包装。如 boost::function等等。但是它也有限制:它所支持的参数仍然是有限的,只有十多个,尽管够你用的了;同样,它也是丑陋的,永远不要想它能够 简单的用&来搞定。

  也许,以失去美丽的代价,来换取质量上的保证,这也是C++对于函数指针的一种无奈吧……

  期待C++0x版本。它通过可变模板参数,能够让mem_fun的参数达到无限个……

--------
   BTW: C++Builder扩展了一个关键字 closure ,允许成员函数指针如同普通函数指针一样使用。也许C++0x能考虑一下……

-------------------------------------------------------

http://www.cnblogs.com/jans2002/archive/2006/10/13/528160.html

http://www.codeproject.com/KB/cpp/FastDelegate.aspx

posted on 2011-11-23 10:09  clq  阅读(728)  评论(3编辑  收藏  举报