【C/C++】【C++11】可调用对象/function/bind

可调用对象

函数指针

void myfunc(int tv)
{
	cout << tv << endl;
}
int main()
{
    void (*func)(int) = myfunc; //定义函数指针并赋值;
	func(10);  //调用函数,可调用对象;
}

仿函数

具有operator()成员函数的类对象
仿函数functor:行为类似于函数;仿函数通过在类中重载()运算符实现,又成为函数对象,能起到函数功能的类;

class Fc
{
public:
	void operator()(int tv)
	{
		cout << tv << endl;
	}
};

int main()
{
    Fc fc;
	fc(20);
}

可被转换为函数指针的类对象

// other.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

//auto类型推断,auto应用场合

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

class Test
{
public:
	using func_p = void(*)(int); //定义一个函数指针类型;
	static void fun(int tv) //静态成员函数;
	{
		cout << tv << endl;
	}
	operator func_p()
	{
		return fun;
	}
};

int main()
{
	Test t;
	t(50); //先调用func_p,在调用静态成员 func_p;//等价于t.operator Test::func_p()(20);
    t.operator Test::func_p()(20);
	return 0;
}

类成员函数指针

// other.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

//auto类型推断,auto应用场合

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

class Fc
{
public:
	void operator()(int tv)
	{
		cout << tv << endl;
	}

	void func(int tv)
	{
		cout << tv << endl;
	}
public:
	int m_a;
};

int main()
{
	Fc fc;
	void (Fc:: *func_p)(int) = &Fc::func; //类成员函数指针变量func_p定义并给初值;
	(fc.*func_p)(68);
	return 0;
}

总结

  • 看成对象;
  • 可以对其使用()调用运算符;

std::function(可调用对象包装器)

  • std::function是个类模板,用来装各种可调用对象,不能装类成员函数指针;
  • 头文件 functional
  • 通过给std::function指定模板参数,它就能用统一的方式处理函数

绑定普通函数


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

void func(int tv)
{
	cout << tv << endl;
}

int main()
{
	std::function<void(int) > f = func;
	f(100);
	return 0;
}

绑定类的静态成员函数

// other.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

//auto类型推断,auto应用场合

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


class Fc
{
public:
	void operator()(int tv)
	{
		cout << tv << endl;
	}

	void func(int tv)
	{
		cout << tv << endl;
	}

	static int static_func(int tv)
	{
		cout << tv << endl;
		return tv;
	}
public:
	int m_a;
};

int main()
{
	std::function<int(int) > f = Fc::static_func;
	f(100);
	return 0;
}

绑定仿函数

// other.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

//auto类型推断,auto应用场合

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


class Fc
{
public:
	void operator()(int tv)
	{
		cout << tv << endl;
	}

	void func(int tv)
	{
		cout << tv << endl;
	}

	static int static_func(int tv)
	{
		cout << tv << endl;
		return tv;
	}
public:
	int m_a = 0;
};

int main()
{
	Fc t;
	std::function<void(int) > f = t;
	f(100);
	return 0;
}

范例1


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

class Other
{
	std::function<void()> callba;
public:
	Other(const std::function<void()>& f) :callba(f)
	{
		int i;
		i = 1;
	}

	void run_call(void)
	{
		callba();
	}
};

class Another
{
public:
	void operator()(void)
	{
		cout << "void operator()(void)" << endl;
	}
};

int main()
{
	Another an; //可调用对象
	Other o(an); //Other需要可调用对象做参数来构造,因为operator可以转为std::fuinction<void()&>
	o.run_call(); //执行Other里的run_call;

	return 0;
}

范例2


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

void call_back(int x, const std::function<void(int) >& f)
{
	f(x);
}
void func(int x)
{
	cout << x << endl;
}
int main()
{
	for (int i = 0; i < 10; ++i)
	{
		call_back(i, func); //func(i)
	}
	return 0;
}

std::bind(绑定器)

  • C++11引入的,类模板;

  • 头文件 functional

  • std::bind能够将对象以及相关的参数绑定到一起,绑定后可以直接调用;也可以使用std::function进行保存,需要的时候再调用;

  • 格式

    std::bind(带绑定的函数对象, 参数1, 参数2, ..., 参数n);
    

范例1


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


void func(int x, int y, int z)
{
	cout << x << " " << y << " " << z << endl;
}
int main()
{
	auto b1 = std::bind(func, 10, 20, 30); //auto不关心bind的返回类型,其实bind返回的是一个仿函数类型对象,可以直接调用,也可以赋值给std::function
	b1(); //执行func函数
	return 0;
}

范例2

#include <iostream>
#include <functional>
using namespace std;
void func(int x, int y, int z)
{
	cout << x << " " << y << " " << z << endl;
}
int main()
{
	//表示绑定函数func的第三个参数为30;
	//第一个和第二个参数分别由调用b1时的第一个和第二个参数指定;
	//placeholders::_1 被调用的时候的第一个参数替代;
	auto b1 = std::bind(func, placeholders::_1, placeholders::_2, 30); 
	b1(10, 20);
	
        std::bind(func, placeholders::_1, placeholders::_2, 30)(10, 20); //直接调用
	return 0;
}

范例3


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


void func(int& x, int& y, int& z)
{
	x++;
	y++;
	z++;
	cout << x << " " << y << " " << z << endl;

}
int main()
{
	//表示绑定函数func的第三个参数为30;
	//第一个和第二个参数分别由调用b1时的第一个和第二个参数指定;
	//placeholders::_1 被调用的时候的第一个参数替代;

	int a = 2, b = 3, c = 4;
	auto b1 = std::bind(func, a, placeholders::_1, c); 
	b1(b);
	cout << a << " " << b << " " << c << endl; // a和c的值没有发生改变;
	//bind对于预先绑定的函数参数是通过值传递的;即a,c
	//bind对于事先先绑定的参数,通过std::placeholders传递的参数,是通过引用传递的;即b
	return 0;
}

范例4


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


class Test
{
public:
	void func(int x, int y)
	{
		cout << x << " " << y << endl;
		m_a = x;
		cout << m_a << endl;
	}
public:
	int m_a = 0;
};
int main()
{
	Test t;
	//bind的第二个参数t,会导致调用Test的拷贝构造函数来生成一个Test类型的临时对象,作为std::bind的返回值(bind返回仿函数类型对象);
	//后续的func调用修改的是临时对象的m_a; 并不影响真实t对象的m_a的值;

	auto b1 = std::bind(&Test::func, t, placeholders::_1, placeholders::_2); 
	b1(2, 3);
	
	//加了&,就不生成临时对象了,后续func调用修改的是t对象的m_a值,此时bind返回的这个对象其实是t对象本身(仿函数类型对象)
	auto b2 = std::bind(&Test::func, &t, placeholders::_1, placeholders::_2);
	b2(2, 3);

	return 0;
}



范例5


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


class Test
{
public:
	void func(int x, int y)
	{
		cout << x << " " << y << endl;
		m_a = x;
		cout << m_a << endl;
	}
public:
	int m_a = 0;
};
int main()
{
	Test t;
	std::function<void(int, int)> b = std::bind(&Test::func, t, std::placeholders::_1, std::placeholders::_2);
	b(10, 20);

	return 0;
}



范例6


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

class Test
{
public:
	Test()
	{
		cout << "Test()" << endl;
	}

	Test(const Test& t)
	{
		cout << "Test(Test& t)" << endl;
		m_a = t.m_a;
	}

	~Test()
	{
		cout << "~Test()" << endl;
	}
	void func(int x, int y)
	{
		cout << x << " " << y << endl;
		m_a = x;
		cout << m_a << endl;
	}
public:
	int m_a = 0;
};
int main()
{
	Test t;
	//把成员变量地址当函数一样绑定,绑定的结果放在std::function<int &(void)> 里保存,就是用一个可调用对象来保存;
	std::function<int& ()> b = std::bind(&Test::m_a, t); //bind第二个参数不是引用,会导致两次Test类拷贝构造函数的执行;
	//1. 利用t产生一个临时的Test对象;
	//2. std::bind本身要返回一个Test对象,要返回的Test对象(仿函数)拷贝自临时的Test对象;但是std::bind执行完毕后,临时Test对象会被释放,返回的这个Test对象(仿函数)拷贝到b中;

	b() = 60;
	return 0;
}

范例7


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

class Test
{
public:
	Test()
	{
		cout << "Test()" << endl;
	}

	Test(const Test& t)
	{
		cout << "Test(Test& t)" << endl;
		m_a = t.m_a;
	}

	~Test()
	{
		cout << "~Test()" << endl;
	}
	void func(int x, int y)
	{
		cout << x << " " << y << endl;
		m_a = x;
		cout << m_a << endl;
	}

public:
	void operator()()
	{
		cout << "void operator()()" << endl;
	}
public:
	int m_a = 0;
};
int main()
{
	auto t = std::bind(Test()); //Test是构造临时对象,然后又调用了拷贝构造函数 生成了一个可调用对象,作为std::bind的返回内容;
	//bind返回仿函数类型对象,就是则会个用拷贝构造函数构造起来的对象;
	t();
	return 0;
}



范例8


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


void callback(int test, const std::function<void(int)>& f)
{
	f(test);
}
void func(int x)
{
	cout << x <<  endl;
}
int main()
{
	auto bind_f = std::bind(func, std::placeholders::_1); //func的第一个参数由调用时候的第一个参数指定;
	for (int i = 0; i < 10; i++)
	{
		callback(i, bind_f);
	}
	return 0;
}

总结

  • std::bind将可调用对象和参数绑定到一起,构成一个仿函数,所以可以直接调用;
  • 如果函数有多个参数,可以绑定一部分参数,其他参数在调用的时候指定;
  • bind思想所谓的延迟调用,将可调用对象统一格式,保存起来,需要的时候再调用;
  • std::function可以绑定要给可调用对象,类型成员不能绑定;std::bind成员函数,成员变量等等都能绑;
posted @ 2020-08-04 20:21  NaughtyCoder  阅读(276)  评论(0)    收藏  举报