//function是一个函数对象的“容器”,概念上像是C++中函数指针类型的泛化,是一种“智能函数指针”。它以对象的形式封装了原始的函数指针或函数对象,能够容纳任意符合函数签名的可调用对象。因此可以用于回调机制,暂时保管函数或函数对象,在之后需要的时机再调用,使回调机制拥有更多的弹性。function可以配合bind使用,存储bind表达式的结果,使bin可以被多次调用。 #pragma once #include <boost/function.hpp> #include <boost/bind.hpp> //#include <iostream> #include <conio.h> using namespace boost; //function的声明:eg:function<int(int,int)>func;//声明一个可以容纳返回值为int类型,2个参数都为int类型的function对象。//它很好理解,<>中的类型声明很像一个函数原型,只是没有函数名 int f(int a,int b){return a+b;}//声明一个二元函数 void test1() { function<int(int,int)> func1(f);//function的构造函数可以接受任意符合模板中声明的函数类型的可调用对象,如普通函数,成员函数,函数指针,函数对象,也可以使另一个function对象的引用,之后在内部存储一份它的拷贝。 function<int(int,int)> func2(*f); function<int(int,int)> func3(&f); function<int(int,int)> func;//无参构造一个function对象,无参的构造函数或者传入空指针构造函数创建一个空的function对象,不持有任何可调用物,调用空的function对象将抛出bad_function_call异常,因此在使用function前最好检测一下它的有效性。可以用empty()或者重载操作符operator!来检测。 if (!func) { std::cout<<"func is null"<<std::endl;//func is null } func=f;//func存储了函数f if (func) { std::cout<<func1(10,20)<<std::endl;//30 std::cout<<func2(10,20)<<std::endl;//30 std::cout<<func3(10,20)<<std::endl;//30 std::cout<<func(10,20)<<std::endl;//30 //调用function的operator,如下一行 std::cout<<func.operator()(10,20)<<std::endl;//30 } func=0;//将func置空,==>>func.clear(); if (func.empty()) { std::cout<<"func is empty"<<std::endl;//fuc is empty } } // struct demo//class也可以,不要忘了加public: { int add(int a,int b){return a+b;}//加法操作 int operator()(int x)const{return x*x;}//重载operator() }; void test2() { //只要函数签名式一致,function可以存储成员函数和函数对象或者是bind表达式的结果 function<int(demo&,int,int)> func1;//可以自己在function声明的函数签名式中指定类的类型,然后用bind绑定成员函数 func1=bind(&demo::add,_1,_2,_3); demo de; std::cout<<func1(de,10,20)<<std::endl;//30 function<int(int,int)> func2;//也可以在函数类型中仅写出函数的签名,在bind是直接绑定类的实例 func2=bind(&demo::add,de,_1,_2);//==>>func2=bind(&demo::add,&de,_1,_2); std::cout<<func2(10,20)<<std::endl;//30 } //使用ref库 void test3() { //function使用拷贝语义保存参数,当参数很大时拷贝的代价往往很高,或者有时候不能拷贝参数。这时我们可以向ref库求助,它允许以引用的方式传递参数,能够降低function拷贝的代价。 demo de;//之前定义的函数对象 function<int(int)> func; func=ref(de); //使用ref()函数包装对象的引用,也可以用cref()来调用const成员函数 std::cout<<func(10)<<std::endl;//100 //调用被引用的对象 } //用于回调 //function可以容纳任意符合函数签名式的可调用物,因此它非常适合代替函数指针,存储用于回调的函数,而且他的强大功能会使代码更灵活,富有弹性。 class demoA { typedef function<void(int)> func_t;//function类型定义 func_t func; //function对象 int n; //内部成员变量 public: demoA(int i):n(i){} //使用模板函数accept()接受回调函数。之所以使用模板函数是因为这种形式更加灵活,用户可以在不知道耶不关心内部存储形式的情况下传递任何可调用对象(eg:函数指针,函数对象) template<typename T> void accept(T f) {func=f;}//存储回调函数 void run(){func(n);}//用于调用回调函数 }; void callbackFunc(int i)//定义一个回调的函数 { std::cout<<"callbackFunc:"<<i*2<<std::endl; } void test4() { demoA de(10); de.accept(callbackFunc);//接受回调函数 de.run();//调用回调函数,输出callbackFunc:20 } //使用普通的C函数进行回调并不能体现function的好处,下面编写一个带状态的函数对象,并使用ref库传递引用 void test5() { class demoB { int x;//内部状态 public: demoB(int i):x(i){} void operator()(int i) { std::cout<<"demoB:"<<i*x++<<std::endl;//先乘法,后递增 } }; demoA de(10); demoB db(2); de.accept(ref(db));//使用ref库 de.run();//demoB:20 de.run();//demoB:30 } //function还可以搭配bind库,把bind表达式作为回调函数,可以接受类成员函数或者不符合函数签名式的函数bind为可接受的形式。 void test6() { class demoC { public: void callbackFunc1(int i) { std::cout<<"callbackFunc1:"<<i*2<<std::endl; } void callbackFunc2(int i,int j) { std::cout<<"callbackFunc2:"<<i*j*2<<std::endl; } }; demoA de(10); demoC dc; de.accept(bind(&demoC::callbackFunc1,dc,_1)); de.run();//callbackFunc1:20 de.accept(bind(&demoC::callbackFunc2,dc,_1,5)); de.run();//callbackFunc2:100 //通过上面的实例,我们可以看到function用于回调的好处,它无需改变回调的接口就可以解耦客户端代码,是客户端代码不必绑死在一种回调形式上,进而可以持续演化,而function始终能够保证与客户端代码正确沟通。 } void test(char t) { std::cout<<"press key====="<<t<<std::endl; switch (t) { case '1':test1();break; case '2':test2();break; case '3':test3();break; case '4':test4();break; case '5':test5();break; case '6':test6();break; case 27: case 'q':exit(0);break; default: std::cout<<"default "<<t<<std::endl;break; } } int main() { while(1) { test(getch()); } return 0; }