c++ 学习之 可调用对象

c++ 学习之 可调用对象

前言

c++中,在使用一些基于范围的模板函数时,常常需要我们传入一个可调用对象,以指明我们需要对范围中的每个元素进行怎样的处理。在thread的初始化中也需要传入可调用对象来作为线程的入口函数。可调用对象也可以作为回调函数使用。可调用对象大概有这么几种:普通函数 ,类成员函数,类静态函数,仿函数,函数指针,lambda表达式,std::function。下面给大家进行简单的介绍。

正文

1.普通函数
普通函数大家最熟悉不过了,我们常常以定义函数的方式,来讲某一段程序封装在一起,来实现某一特定的功能。以下这种就是普通函数:

#include<stdio.h>
int Add(int a,Int b)
{
   return a+b;
}
int main()
{
   printf("%d\n",Add(1,3));
}

我们通过调用Add函数来得到两个整数的相加结果。

2.类成员函数
类中定义的函数有两种,一种是类静态函数,另一种是类成员函数。不像类成员变量,两者都有真实的地址。只不过类成员函数中隐含了this指针,也就是说可以在可以在函数内部隐式或显式的使用this指针来调用类的非静态成员。并且类成员函数必须依附于类对象使用,也就是说,在没有对象实例的前提下,是无法通过函数地址使用该函数的

#include<stdio.h>
class A
{
public: 
  int a ;
  A(int a)
  {
   this->a =a ;
  }
  void fun()
  {
  printf("%d\n",a);
  }

};
int main()
{
  A a(10);
  a.fun();
  //A::fun();错误用法!!!
}

输出结果:10

3.类静态函数
上文说到的类中两种函数,类静态函数就是另一种。它与类成员函数最大的不同,就是它不可以调用类中的非静态成员,也不可以使用this指针,但是可以不用创建类对象,直接通过函数地址调用。

#include<stdio.h>
class A
{
  public:
   static int a;
   static int Add(int b)
   {
    return A::a + b;
   }
};
int A::a =1;
int main()
{
    printf("%d\n",A::Add(2));
}

输出结果 : 3
可以看到,我们没有创建类的对象,通过直接使用类中的静态函数Add得到类中的静态成员a和2的和。

4.仿函数
通过在类内定义运算符重载函数,用类实现函数调用。

#include<stdio.h>
class A
{
 public:
   int operator()(int a,int b)
   {
    return a+b;
   }
};
int main()
{
   A a;
   printf("%d\n",a(1,2));
}

输出结果 : 3
通过在类内部重载(),用类模拟函数的调用。

5.函数指针
函数指针大家并不陌生,我们使用回调函数可以通过函数指针来实现。下面举个例子吧。

#include<stdio.h>
typedef int(*P)(int ,int);
int Add(int a,int b)
{
 return a+b;
}
int fun(int p (int,int),int a,int b)
{
 return  p(a,b);
}
int main()
{
 P pAdd = Add;
 int a =1;
 int b =2;
 printf("%d\n", fun(pAdd, a, b));
}

输出结果 :3
虽然这个例子有点牵强,但是意在理解嘛,就是让大家明白,函数指针的使用。往往很多地方需要这样传入一个函数指针作为参数,这样使用就是避免不了的了。其实也可以用函数名作为参数

6.lambda表达式

lambda 表达式是一种匿名函数,即没有函数名的函数,通常情况下,lambda函数的语法定义为:
[capture] (parame) mutable ->return-type {statement}
其中:
[captures]为捕获列表,用于捕获外层变量
(parame)为匿名函数参数列表
mutable修饰符可以取消返回值的常量性
return-type为返回值类型
{statement}为函数体
通常情况下:
* 可以用auto来定义
* 若没有参数,(parame)可以省略;
* 在默认的情况下,lambda函数总是返回一个const,而当我们在参数列表后面注明了“mutable”关键字之后,则可以取消其常量性质,当我们使用mutable时,(parame)不可以省略,即便参数为空(mutable可以省略);
* return-type可以省略。
* [captures]捕获项可以有0项或多项:
[] 不捕获任何变量
[&] 捕获外部作用域中所有变量,并作为引用在匿名函数体中使用
[=] 捕获外部作用域中所有变量,并拷贝一份在匿名函数体中使用
[&, x] x按值捕获. 其它变量按引用捕获
[=, &y] y按引用捕获. 其它变量按值捕获
[this] 捕获当前类中的this指针,如果已经使用了&或者=就默认添加此选项

*只有lambda函数没有指定任何捕获时,才可以显式转换成一个具有相同声明形式函数指针

#include<stdio.h>
int main()
{
 int a = 1;
 int b = 2;
 auto Swap = [&]() {int temp = a; a = b; b = temp; };
 Swap();
 printf("%d %d\n", a, b);
}

通过匿名函数以引用的方式捕获a,b,在函数中交换a与b的值。
注意,匿名函数在c++ 11 中是inline(内联)的

7.std::function
std::function 可以用来描述C++中的可调用实体,它可以兼容所有具有相同参数类型的函数实体。需要引入<functional>头文件,声明方式如下:
std::function<Type(type1,type2)> name
下面举几个其他可调用对象转换为std::function的例子:

#include<stdio.h>
#include<functional>
std::function<void(int, int)> Function;
//普通函数
void fun(int a,int b)
{
 printf("普通函数:%d\n", a + b);
}
void fun2(int a, int b)
{
 printf("函数指针:%d\n", a + b);
}
class A
{
public:
 //类成员函数
 void fun1(int a, int b)
 {
  printf("类成员函数:%d\n", a + b);
 }
 //静态成员函数
 static void fun2(int a, int b)
 {
  printf("静态成员函数:%d\n", a + b);
 }
 //仿函数
 void operator ()(int a, int b)
 {
  printf("仿函数(类对象):%d\n", a + b);
 }
};
int main()
{
  int a =1;
  int b =2;
  Function = fun;
  Function(a,b);
 
  void (*p)(int,int) = fun2;
  Function = p;
  Function(a,b);
 
  A c;
  Function = std::bind(&A::fun1,c,std::placeholders::_1,std::placeholders::_2);  
  Function(a,b);


 Function  = &A::fun2;
 Function(a,b);

  A d;
  Function = d;
  Function(a,b); 

  auto lam = [](int a,int b){ printf("lambda表达式:%d\n",a+b);};
  Function = lam;
  Function(a,b);
}

其中需要注意对于类成员函数,因为类成员函数包含this指针参数,所以需要结合使用std::bind函数绑定this指针以及参数列表。
上面例子中:
Function = std::bind(&A::fun1,c,std::placeholders::_1,std::placeholders::_2);
*第一个参数为类成员函数名的引用
*第二个参数为this指针上下文,即特定的对象实例
*使用std::placeholders::_1表示使用调用过程的第1个参数作为成员函数参数,std::placeholders::_n表示调用时的第n个参数。

Function = std::bind(&A::fun1,c,std::placeholders::_1,10);
Function(5);

输出结果 15

Function = std::bind(&A::fun1,c,510);
Function();

输出结果 15

Function = std::bind(&A::fun1,c,std::placeholders::_2,std::placeholders::_1);
Function(5,10);

输出结果 15
这样的参数进去,a = 10, b = 5。

发布了10 篇原创文章 · 获赞 6 · 访问量 414

猜你喜欢

转载自blog.csdn.net/weixin_45074185/article/details/104384311