代码改变世界

如何传递成员函数指针参数

2011-07-13 17:02  bingcaihuang  阅读(3827)  评论(0编辑  收藏  举报
在C++中,成员函数指针作为参数传递给其他函数和普通函数指针的传递是不同的,首先我们来回顾一下普通函数指针的传递方法: 
//--------------------------------------------------------------------------- 
int   fun1(int   i){ 
                return   i; 


void   fun2(int   j,   int   (*p)(int)){ 
                cout   < <   p(j); 


void   main() 

                int   i=1; 
                fun2(i,fun1); 

//--------------------------------------------------------------------------- 
只要在参数声明中声明是相同参数个数、类型和相同返回类型的函数指针int   (*p)(int),传递时只需传函数名就可以了 

可是为什么在C++中,传递成员函数指针用此方法却不能工作呢?我们先来回顾一下指针的概念,指针是指向一些内存地址的变量,既可以是数据的地址也可以是函数的地址。C++的   成员指针遵从同样的原则。困难的是所有的指针需要一个地址,但在类内部没有地址;选择一个类的成员意味着在类中偏移。只有把这个偏移和具体对象的开始地址结合,才能得到实际地址。成员指针的语法要求选择一个对象的同时逆向引用成员指针。 
先来看看一个错误的例子: 
//--------------------------------------------------------------------------- 
class   A 

public: 
                int   fun1(int   i){return   i;}; 
}; 

void   fun2(int   j,   int   (A::*p)(int)){ 
                cout   < <p(j); 


void   main() 

                A   oba; 
                int   i=1; 
                fun2(i,oba.fun1);     //this   is   an   error 

//--------------------------------------------------------------------------- 

当然,你可以把成员函数声明为static(静态函数),这样传递它的指针就像传递普通函数一样,然而把成员函数定义成static类型无法真正解决问题,因为这样的话,该成员函数就不能存取类中的非静态成员变量,而很多情况下既要求传递成员函数指针,又要求该成员函数能够存取类中的非静态成员变量。 

为了能够正确地传递成员函数指针,我们先来看看成员参数、成员函数指针正确的声明方法: 
//--------------------------------------------------------------------------- 
class   A 

public: 
int   i1; 
                int   fun1(int   i){ 
                                return   i; 
                }; 
}; 

void   main() 

int   (A::*fp1)(int);         //声明fp1为class   A中的成员函数指针 
                int   A::*ip1;                       //声明ip1为class   A中的成员变量指针 
fp1=&A::fun1;                     //初始化fp1 
ip1=&A::i1;                         //初始化ip1   
A   oba; 
oba.*ip1=2; 
(oba.*fp1)(oba.*ip1); 

//--------------------------------------------------------------------------- 

接下来就可以构造含有成员函数指针参数的函数了: 
void   fun2(int   j,   A   ob,   int   (A::*p)(int)){ 
                cout   < <(ob.*p)(j); 

注意声明时必须加上一个对象参数A   ob,因为只有把这个偏移和具体对象的开始地址结合,才能得到实际地址。 

另外,为了保证函数的健壮性和经济性,我们可以把对象参数改为对象指针参数: 
void   fun2(int   j,   A   *obp,   int   (A::*p)(int)){ 
                cout   < <(obp-> *p)(j); 


为了通用,我们还可以把这个函数声明为通用函数: 
template   <class   T> 
void   fun2(int   j,   T   *obp,   int   (A::*p)(int)){ 
                cout   < <(obp-> *p)(j); 

这样就可以传递不同的类的成员函数指针给它了,以下为正确传递成员函数指针的例程: 
//--------------------------------------------------------------------------- 
class   A 

public: 
                int   fun1(int   i){ 
                                return   i; 
                }; 
}; 

template   <class   T> 
void   fun2(int   j,   T   *obp,   int   (T::*p)(int)){ 
                cout   < <(obp-> *p)(j); 


void   main() 

                int   (A::*fp1)(int); 
                fp1=&A::fun1; 
                A   oba; 
A   *obap=&oba; 
int   i=1; 
                fun2(i,obap,fp1); 

//--------------------------------------------------------------------------- 

但是这样声明之后就不能再传递普通函数指针给函数fun2了,为了更加通用,当然可以显式地重载一下这个函数,以便它也能使用普通函数指针参数: 
//--------------------------------------------------------------------------- 
class   A 

public: 
                int   fun1(int   i){ 
                                return   i; 
                }; 
}; 

template   <class   T> 
void   fun2(int   j,   T   *obp,   int   (T::*p)(int)){ 
                cout   < <(obp-> *p)(j); 


void   fun2(int   j,   int   (*p)(int)){ 
                cout   < <   p(j); 


int   fun3(int   i){ 
                return   i; 


void   main() 

                int   (A::*fp1)(int); 
                fp1=&A::fun1; 
                A   oba; 
A   *obap=&oba; 
int   i=1; 
                fun2(i,obap,fp1); 
fun2(i,fun3); 

//--------------------------------------------------------------------------- 
(全文完)