类成员函数
在一个类class中定义的函数一般称为类的方法,分为成员方法和静态方法,区别是成员方法的参数列表中隐含着类this指针。
#include
classCalcu
{
public:
intbase=20;
//类的成员方法,参数包含this指针
intclass_func_add(constinta,constintb)const{returnthis->base+a+b;};
//类的静态成员方法,不包含this指针
staticintclass_static_func_add(constinta,constintb){returna+b;};
};
intmain(void)
{
Calcuobj;
inta=10;
intb=20;
//类普通成员方法调用如下
obj.class_func_add(a,b);
//类静态成员方法调用如下
obj.class_static_func_add(a,b);
Calcu::class_static_func_add(a,b);
getchar();
return0;
}
仿函数
仿函数是使用类来模拟函数调用行为,我们只要重载一个类的operator()方法,即可像调用一个函数一样调用类。这种方式用得比较少。
classImitateAdd
{
public:
intoperator()(constinta,constintb)const{returna+b;};
};
intmain()
{
//首先创建一个仿函数对象,然后调用()运算符模拟函数调用
ImitateAddimitate;
imitate(5,10);
getchar();
return0;
}
函数指针
顾名思义,函数指针可以理解为指向函数的指针。可以将函数名赋值给相同类型的函数指针,通过调用函数指针实现调用函数。
函数指针是标准的C/C++的回调函数的使用解决方案,本身提供了很大的灵活性。
#include
//声明一个compute函数指针,函数参数为两个int型,返回值为int型
int(*compute)(int,int);
intmax(intx,inty){returnx>=y?x:y;}
intmin(intx,inty){returnx<=y?x:y;}
intadd(intx,inty){returnx+y;}
intmultiply(intx,inty){returnx*y;}
//一个包含函数指针作为回调的函数
intcompute_x_y(intx,inty,int(*compute)(int,int))
{
//调用回调函数
returncompute(x,y);
}
intmain(void)
{
intx=2;
inty=5;
std::cout<<"max:"<int{returnx+y;};
std::cout<<"sum:"<
Lambda函数
Lambda函数定义
Lambda函数,又可以称为Lambda表达式或者匿名函数,在C++11中加入标准。定义形式如下:
[captures](params)->return_type{statments;}
其中:
- [captures]为捕获列表,用于捕获外层变量
- (params)为匿名函数参数列表
- ->return_type指定匿名函数返回值类型
- {statments;}部分为函数体,包括一系列语句
需要注意:
- 当匿名函数没有参数时,可以省略(params)部分
- 当匿名函数体的返回值只有一个类型或者返回值为void时,可以省略->return_type部分
- 定义匿名函数时,一般使用auto作为匿名函数类型
下面都是有效的匿名函数定义
autofunc1=[](intx,inty)->int{returnx+y;};
autofunc2=[](intx,inty){returnx>y;};//省略返回值类型
autofunc3=[]{global_ip=0;};//省略参数部分
Lambda函数捕获列表
为了能够在Lambda函数中使用外部作用域中的变量,需要在[]中指定使用哪些变量。
下面是各种捕获选项:
- []不捕获任何变量
- [&]捕获外部作用域中所有变量,并作为引用在匿名函数体中使用
- [=]捕获外部作用域中所有变量,并拷贝一份在匿名函数体中使用
- [x,&y]x按值捕获,y按引用捕获
- [&,x]x按值捕获.其它变量按引用捕获
- [=,&y]y按引用捕获.其它变量按值捕获
- [this]捕获当前类中的this指针,如果已经使用了&或者=就默认添加此选项
只有lambda函数没有指定任何捕获时,才可以显式转换成一个具有相同声明形式函数指针
autolambda_func_sum=[](intx,inty){returnx+y;};//定义lambda函数
void(*func_ptr)(int,int)=lambda_func_sum;//将lambda函数赋值给函数指针
func_ptr(10,20);//调用函数指针
std::function函数包装
std::function定义
std::function在C++11后加入标准,可以用它来描述C++中所有可调用实体,它是是可调用对象的包装器,声明如下:
#include
//声明一个返回值为int,参数为两个int的可调用对象类型
std::functionFunc;
使用之前需要导入库,并且通过std命名空间使用。
其他函数实体转化为std::function
std::function强大的地方在于,它能够兼容所有具有相同参数类型的函数实体。
相比较于函数指针,std::function能兼容带捕获的lambda函数,而且对类成员函数提供支持。
#include
#include
std::functionSumFunction;
//普通函数
intfunc_sum(inta,intb)
{
returna+b;
}
classCalcu
{
public:
intbase=20;
//类的成员方法,参数包含this指针
intclass_func_sum(constinta,constintb)const{returnthis->base+a+b;};
//类的静态成员方法,不包含this指针
staticintclass_static_func_sum(constinta,constintb){returna+b;};
};
//仿函数
classImitateAdd
{
public:
intoperator()(constinta,constintb)const{returna+b;};
};
//lambda函数
autolambda_func_sum=[](inta,intb)->int{returna+b;};
//函数指针
int(*func_pointer)(int,int);
intmain(void)
{
intx=2;
inty=5;
//普通函数
SumFunction=func_sum;
intsum=SumFunction(x,y);
std::cout<<"func_sum:"<int{returnx+y+base;};
SumFunction=lambda_func_with_capture_sum;
sum=SumFunction(x,y);
std::cout<<"lambda_func_with_capture_sum:"<
最后的输出如下:
func_sum:7
Calcu::class_func_sum:27
Calcu::class_static_func_sum:7
lambda_func_sum:7
lambda_func_with_capture_sum:17
imitatefunc:7
functionpointer:7
其中需要注意对于类成员函数,因为类成员函数包含this指针参数,所以单独使用std::function是不够的,还需要结合使用std::bind函数绑定this指针以及参数列表。
std::bind参数绑定规则
在使用std::bind绑定类成员函数的时候需要注意绑定参数顺序:
//承接上面的例子
SumFunction=std::bind(&Calcu::class_func_sum,obj,
std::placeholders::_1,std::placeholders::_2);
SumFunction(x,y);
- 第一个参数为类成员函数名的引用(推荐使用引用)
- 第二个参数为this指针上下文,即特定的对象实例
- 之后的参数分别制定类成员函数的第1,2,3依次的参数值
- 使用std::placeholders::_1表示使用调用过程的第1个参数作为成员函数参数
- std::placeholders::_n表示调用时的第n个参数
看下面的例子:
//绑定成员函数第一个参数为4,第二个参数为6
SumFunction=std::bind(&Calcu::class_func_sum,obj,4,6);
SumFunction();//值为10
//绑定成员函数第一个参数为调用时的第一个参数,第二个参数为10
SumFunction=std::bind(&Calcu::class_func_sum,obj,std::placeholders::_1,10);
SumFunction(5);//值为15
//绑定成员函数第一个参数为调用时的第二个参数,第一个参数为调用时的第二个参数
SumFunction=std::bind(&Calcu::class_func_sum,obj,std::placeholders::_2,std::placeholders::_1);
SumFunction(5,10);//值为15
对于非类成员对象,一般直接赋值即可,会自动进行转换并绑定参数,当然也可以使用std::bind指定参数绑定行为;
#include
#include
//按照顺序输出x,y,x
voidprint_func(intx,inty,intz)
{
std::cout<Func;
intmain()
{
Func=std::bind(&print_func,1,2,3);
Func(4,5,6);//输出:123
Func=std::bind(&print_func,std::placeholders::_2,std::placeholders::_1,3);
Func(1,2,7);//输出:213
intn=10;
Func=std::bind(&print_func,std::placeholders::_1,std::placeholders::_1,n);
Func(5,6,7);//输出:5510
getchar();
return0;
}
需要注意:就算是绑定的时候指定了默认参数,在调用的时候也需要指定相同的参数个数(虽然不会起作用),否则编译不通过。
关于回调函数
回调就是通过把函数等作为另外一个函数的参数的形式,在调用者层指定被调用者行为的方式。
通过上面的介绍,我们知道,可以使用函数指针,以及std::function作为函数参数类型,从而实现回调函数:
#include
#include
std::functionComputeFunction;
int(*compute_pointer)(int,int);
intcompute1(intx,inty,ComputeFunctionfunc){
//dosomething
returnfunc(x,y);
}
intcompute2(intx,inty,compute_pointerfunc)
{
//dosomething
returnfunc(x,y);
}
//调用方式参考上面关于函数指针和std::function的例子
以上两种方式,对于一般函数,简单lambda函数而言是等效的。
但是如果对于带有捕获的lambda函数,类成员函数,有特殊参数绑定需要的场景,则只能使用std::function。
其实还有很多其他的实现回调函数的方式,如下面的标准面向对象的实现:
#include
//定义标准的回调接口
classComputeFunc
{
public:
virtualintcompute(intx,inty)const=0;
};
//实现回调接口
classComputeAdd:publicComputeFunc
{
public:
intcompute(intx,inty)constoverride{returnx+y;}
};
intcompute3(intx,inty,constComputeFunc&compute)
{
//调用接口方法
returncompute.compute(x,y);
}
//调用方法如下
intmain()
{
ComputeAddadd_func;//创建一个调用实例
intsum=compute3(3,4,add_func);//传入调用实例
}
面向对象的方式更加灵活,因为这个回调的对象可以有很复杂的行为。
以上三种方法各有各的好处,根据你需要实现的功能的复杂性,扩展性和应用场景等决定使用。
另外,这些函数类型的参数可能为空,在调用之前,应该检查是否可以调用,如检查函数指针是否为空。
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对毛票票的支持。