C++——将成员函数作为参数
2015-10-23 12:22
363 查看
在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
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);
}
//--------------------------------------------------------------------------
我们来回顾一下普通函数指针的传递方法:
//--------------------------------------------------------------------------
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
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);
}
//--------------------------------------------------------------------------
相关文章推荐
- Leetcode Next Permutation
- c++ de-mangle 反编译器命名工具:c++filt
- C++笔试题 字符串的比较,全排列,类似 和分解的问题
- 所用的软件是visualc++6.0绿色版,点击运行后出现[local]1[/local]
- c语言学习之基础知识点介绍(五):关系运算式和逻辑运算式
- 微软承诺将在今年的 Visual C++ 更新中加入 Clang 编译器
- LoadRunner 常用C语言函数使用
- c++, windows系统 复制粘贴 任意字符名称 文件
- 1028. 人口普查(20)
- c++问题之-- MessageBoxW”: 不能将参数 2 从“char [20]”转换为“LPCWSTR”
- C++-----------------------------------------------------std::bind
- memmove与memcpy区别
- configure: error: C++ preprocessor "/lib/cpp" fails sanity check
- c++问题之--This function or variable may be unsafe. Consider using sprintf_s instead
- c语言中的函数的定义以及相关的调用、嵌套、递归以及和数组的关系
- C++项目编译后生成哪些文件?
- C++好书列表
- 浅谈C++多态性
- C++线程池的实现(二)
- c++学习笔记(八):运算符重载的推演