C++的函数指针function以及函数绑定bind使用方法

function可作为方法指针承接方法,这在设计函数回调的时候非常有用,与之配合的好兄弟bind可以绑定方法到function类型

#include <iostream>
#include <functional>

namespace Test {
	//  全局方法区
#pragma region functions

	int add(int a, int b) {  //  一个超简单的方法
		return a + b;
	}

	void TestFunc1(int a, int b) {  //  注意这里是复制传入
		std::cout << a << "," << b << std::endl;
	}
	void TestFunc2(int& a) {  //  这里是引用传入
		std::cout << a << std::endl;
	}

	struct divide
	{
		int operator()(int a, int b) {  //  重载运算符
			return a / b;
		}
	};
#pragma endregion

	//  定义区
#pragma region define
	class MyType {
	public:
		MyType() {};
	};

	class A {
	public:
		using CallbackFn = std::function<void(MyType&)>;
		static A* Create();
		virtual void SetCallback(const CallbackFn& callback) = 0;
	};

	class B : public A
	{
	public:
		CallbackFn callBack;
		inline void SetCallback(const CallbackFn& callback) override { callBack = callback; }
	};

	A* A::Create() {
		return new B();
	}

	class TestClass
	{
	public:
		A* m_A;
		void CallBack(MyType& e);
		TestClass();
	};
#pragma endregion

	//  实现区
#pragma region realize

	void TestClass::CallBack(MyType& e) {
		std::cout << "called" << std::endl;
	}

	TestClass::TestClass() {

		m_A = A::Create();  //  这里在bind时就必须要传入this参数,具体是为什么不清除,不然编译不过
		const Test::B::CallbackFn& callbackFun = std::bind(&TestClass::CallBack, this, std::placeholders::_1);
		m_A->SetCallback(callbackFun);  
		//  用了一种编程手法,new子父接,父中写好纯虚方法,看似操作父实际操作子
		B* ww = dynamic_cast<B*>(m_A);  //  在调用子类中存储的方法是要先转型,推荐使用dynamic_cast,主要用于类层次间的上下行转换,自动类型检查对齐
		MyType* mt = new MyType();
		ww->callBack(*mt);  //  调用方法要满足方法参数  输出called
	}

#pragma endregion

}
int main() {
	std::function<int(int, int)> f1 = Test::add;//函数指针
	std::function<int(int, int)> f2 = Test::divide();//函数对象类的对象
	std::function<int(int, int)> f3 = [](int a, int b) {return a * b; };//lambda表达式
	std::cout << f1(1, 2) << std::endl;;  //  可以这样直接调用函数指针,和调用函数是一样的  输出3

	//  bind绑定函数,基础结构是这样的,第一个参数写要绑定的函数名,加不加&好像没区别,注意要标明函数的作用区间(Test::)这个很重要
	//  后面的参数是占位符,因为我这个方法要传入两个int类型参数所以用两个占位符
	std::function<void(int, int)> bindFunc1 = bind(Test::TestFunc1, std::placeholders::_1, std::placeholders::_2);
	bindFunc1(5, 8);  //  输出5,8

	std::function<void(int&)> bindFunc2 = std::bind(&Test::TestFunc2, std::placeholders::_1);
	int temp = 6;  //  因为这里是引用传值所以必须传入左值,不能像上面那样了
	bindFunc2(temp);  //  右值转左值的办法很简单,定义个变量就好了

	//  在类的内部使用bind时在参数区不太一样,这里调用了TestClass的构造方法,请移步到方法实现
	Test::TestClass* tc = new Test::TestClass();
}

看了或跑了上面的代码后,是不是会出现一个问题,function已经是函数指针了,我为什么需要bind再重新绑定一个函数出来呢?比如这些地方完全可以这么写

	std::function<void(int, int)> bindFunc1 = bind(Test::TestFunc1, std::placeholders::_1, std::placeholders::_2);
直接这样替换
	std::function<void(int, int)> bindFunc1 = Test::TestFunc1;

确实上面这里使用bind看起来可能是自找麻烦,如果你这么认为那还是对function不够了解,在类中是不能这么赋值的,没错,就是因为那个this参数,如果这里这么替换就会编译报错

		const Test::B::CallbackFn& callbackFun = std::bind(&TestClass::CallBack, this, std::placeholders::_1);
替换为下面这行编译不过
		const Test::B::CallbackFn& callbackFun = TestClass::CallBack;

所以需要bind的地方就来了,在类中只能采用bind写法,而且,我认为bind真正的便捷体现在宏定义中,比如我定义这样一个宏来处理类中的bind,类外用不用bind无所谓所以不用了,还简洁

#define BIND_EVENT_FN(x) std::bind(&Test::x, this, std::placeholders::_1)

x是直接替换过去的字符串,这样就可以用宏在类中处理大量的bind,在定义上面的宏之后下面这两行是等效的

		const Test::B::CallbackFn& callbackFun = std::bind(&TestClass::CallBack, this, std::placeholders::_1);
等效
		const Test::B::CallbackFn& callbackFun = BIND_EVENT_FN(TestClass::CallBack);
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值