C++函数对象包装器function类详解

函数对象包装器是对函数的封装,为函数对象提供一个容器,一个封装。C++中现有的可调用实体的一种类型安全的包装(相对来说,函数指针的调用不是类型安全的),换句话说,函数对象包装器就是函数的容器。

当我们有了函数的容器之后便能够更加方便的将函数、函数指针作为对象进行处理。直接调用函数包装器,传值,就可以调用函数。

函数对象包装器支持4种函数的封装

1.普通函数

2.匿名函数

3.类的成员函数

4.仿函数(重载了运算符的函数)

=========================================

1.普通函数的对象包装器

include "stdafx.h"
#include <algorithm>
#include <iostream>
#include <vector>
#include <funtional>

using namespace std;


int printf1(int value1,int value2)
{
   
   int ret = value1+value2;
   printf("普通函数的类对象包装器");
   printf("ret = %d",ret);
   return value;
}

int main()
{

   printf1(3,5);
   std::function<int(int)> function1 = printf1;

   function1(3,6);

   return 0;

}

===============================================================

2.匿名函数的对象包装器

Lambda的本质是一个特殊的,匿名的类类型。它是一个带有operator()的类,即仿函数。仿函数opratoer就是使一个类的使用看上去像一个函数,其实现就是类中实现一个operator(),这个类有了类似函数的行为,就是一个仿函数类了。

仿函数是一个重载了 operator() 运算符、能行使函数功能的类,这个类也称为函数对象类,这个类的对象就是函数对象。函数对象本质上是一个对象,但其使用形式看起来和函数调用一样

Lambda表达式具体形式如下:

[capture](parameters)->return-type{body}

最简单的匿名函数是[](){},它没有参数也没有返回值。在匿名函数中,[]里面用来捕获函数外部的变量,而()里面就是匿名函数的参数,{}里面就是函数的执行代码。

auto + 名字 =[]()->返回值{};
具体介绍:
1.[ ] 中括号表示函数对象的构造函数中是否接收外部变量。 
  [&] 表示使用引用的方式获取外部变量 
  [=] 表示使用值的拷贝的方式获取外部变量。

2.() 这个小括号是就函数对象中的小括号符后面的参数列表。

3.->返回值,需要就放,不需要就不放。根据自己需要,任君选择。

4.{...} 就是函数对象的小括号运算符的函数体。

Lambda表达式实现例子

class Addnum{
  public:

    AddNum(int x):num_(num){};
    //int addNum(int x) const {
      //return num_ + x ;
    //}

   int operator(){int x} const{
   return num_ + x;
   }
}

int main()
{
    //operator
    auto add_num = AddNum(10);
   //auto x = add_num.addNum(5);
   auto x = add_num(5);
   std::cout<<"x:"<<x<<std::endl;

   //lambda
   //替代掉Addnum类
   auto add_num2 = [lamada_num =10](int x){return lamada_num +10};

   auto lamada_x = add_num_2(5);
   std::cout<<"lamada x:"<<lamada_x <<std::endl;

}

========================================================

lamada函数的对象包装器

#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>
using namespace std;

int printf1(int value1,int value2)
{
   
   int ret = value1+value2;
   printf("普通函数的类对象包装器");
   printf("ret = %d",ret);
   return value;
}


class Printf_source {
public:
	Printf_source() {}                   //构造函数

	/*****************************************
     //operator()仿函数替代了My_Printf_source函数
     int My_Printf_source(int n1,int n2) {
		 int ret = n1+n2;
         printf("普通函数的类对象包装器");
         printf("ret = %d",ret);
         return ret;
	}
    *********************************************/
	//仿函数 ---------------------------------------------------------代替My_Printf_source函数
	int operator()(int n1,int n2) {
		 int ret = n1+n2;
         printf("普通函数的类对象包装器");
         printf("ret = %d",ret);
         return ret;
	}

};


int main()
{
    //函数对象包装器:
	//为了函数提供了一种容器(封装),存放在对象或者变量中	
    printf1(3,5);          //打印出8

   //普通函数的封装
   //<int >返回值;(int)参数列表;	
   std::function<int(int)> function1 = printf1;
   function1(3,6);         //打印出9

   //匿名函数
	function<int(int)>function2 = [](int n1,int n2)->int {
		int ret = value1+value2;
        printf("类对象包装器");
        printf("ret = %d",ret);
        return ret;
	};
	function2(7,8);       //打印出15

   return 0;

}

========================================================

再看个下面的例子,将对象包装器做为参数传递的情况

#include <iostream>
#include<functional>	//提供function模板类


//传统C函数
int c_function(int a, int b)
{
	return a + b;
}


//函数对象
class Functor
{
public:
	int operator()(int a, int b)
	{
		return a + b;
	}
};

//用函数指针做参数
typedef int (*pfun)(int, int);

//函数的第一个参数只能接收函数指针
void show1(pfun f, int a, int b)
{
	std::cout << f(a, b) << std::endl;
}

//用function<...>做参数
//函数第一个参数可以接收任何返回值为int,参数为int,int的可调用类型
void show2(std::function<int(int, int)> f, int a, int b)
{
	std::cout << f(a, b) << std::endl;
}
int main()
{
	show1(c_function, 3, 6);		//输出9
	//show1(Functor(), 3, 3);		//编译错误,因为Functor()不能转换为函数指针
	show2(c_function, 3, 5);		//输出8
	show2(Functor(), 3, 3);			//输出6
	system("pause");
}

==================================================

对象包装器的赋值操作

成员函数指针是一种指向类的非静态成员函数的指针。它的类型声明需要加上类名

  • 静态成员函数:取出静态成员函数的地址时,需要通过类名,但&不是必须的;

  • 非静态成员函数:取出非静态成员函数的地址时,需要通过类名,但&是必须的。非静态成员函数的第一个参数是this指针(它是隐藏的),因此在包装时需要指明第一个形参的类型为类的类型。

    #include <iostream>
    #include<functional>

    //测试用函数
    int Minus(int a, int b)
    {
    return a - b;
    }

    //测试用类
    class A
    {
    public:
    int operator()(int a, int b)
    {
    return a * b;
    }
    void show(int a, int b)//普通成员函数
    {
    std::cout << a << " " << b << std::endl;
    }
    static void staticshow(int a, int b)//静态成员函数
    {
    std::cout << a << " " << b << std::endl;
    }
    };
    int main()
    {
    using namespace std::placeholders;
    A a;

      //(1)function<>赋值类成员函数
      //第一种方法
      // 非静态成员函数包含一个隐藏的this指针,所以形参需要多定义一个类型A
      std::function<void(A&, int, int)> f1(&A::show);
      f1(a, 3, 6);	//输出:3  6
    
      //第二种方法
      // 非静态成员函数包含一个隐藏的this指针,所以形参需要多定义一个类型A
      std::function<int(A, int, int)> f1 = &A::show;
      f1(A(), 3, 6);
    
      //*********************************************************************************
    
      //(2)function<>赋值类静态成员函数
      //第一种方法
      std::function<void(int, int)> f2(&A::staticshow);
      f2(6, 6);//输出:6  6
      
       //第二种方法
      std::function<int(int,int)> f2 = A::staticshow; 
    
      //*********************************************************************************
    
      //(3)function<>赋值bind
      //如果函数有多个参数,可以绑定部分参数,其他的参数在调用的时候指定
      std::function<int(int)> f3 = std::bind(Minus, 10, _1);
      std::cout << f3(1) << std::endl;	//输出:9
    
      //*********************************************************************************
    
      //(4)function<>赋值Lambda表达式
      std::function<int(int, int)> f4 = [](int a, int b) {return a + b; };
      std::cout << f4(3, 9) << std::endl;	//输出:12
    
      //*********************************************************************************
    
      //(5)function<>赋值函数对象
      //第一种方法
      std::function<int(int, int)> f5 = A();
      std::cout << f5(6, 6) << std::endl;	//输出:36
    
      //第二种方法
      std::function<int(int, int)> f5 = a;
      std::cout << f5(6, 6) << std::endl;	//输出:36
      system("pause");
    

    }

相关推荐
Amor风信子9 分钟前
华为OD机试真题---跳房子II
java·数据结构·算法
我是陈泽12 分钟前
一行 Python 代码能实现什么丧心病狂的功能?圣诞树源代码
开发语言·python·程序员·编程·python教程·python学习·python教学
Mr.Z.41119 分钟前
【历年CSP-S复赛第一题】暴力解法与正解合集(2019-2022)
c++
优雅的小武先生23 分钟前
QT中的按钮控件和comboBox控件和spinBox控件无法点击的bug
开发语言·qt·bug
Death20023 分钟前
使用Qt进行TCP和UDP网络编程
网络·c++·qt·tcp/ip
戊子仲秋26 分钟前
【LeetCode】每日一题 2024_10_2 准时到达的列车最小时速(二分答案)
算法·leetcode·职场和发展
邓校长的编程课堂28 分钟前
助力信息学奥赛-VisuAlgo:提升编程与算法学习的可视化工具
学习·算法
虽千万人 吾往矣29 分钟前
golang gorm
开发语言·数据库·后端·tcp/ip·golang
创作小达人32 分钟前
家政服务|基于springBoot的家政服务平台设计与实现(附项目源码+论文+数据库)
开发语言·python
郭二哈34 分钟前
C++——list
开发语言·c++·list