成员函数指针作为参数传递给其他函数和普通函数指针的传递

在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);
}
//---------------------------------------------------------------------------
(全文完)
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值