C++委托实现(函数指针,function+bind,委托模式)
来源:互联网 发布:淘宝面单打印软件 编辑:程序博客网 时间:2024/06/08 03:58
这一段在公司的某个框架代码中看到了函数指针的使用。风格比较偏纯C,其实C++有更加合适的解决方案,在这里总结一下。
首先从函数指针说起。
一、函数指针
从定义上讲,函数指针指向的是函数而非对象,函数指针指向某种特定类型。其类型由函数的返回类型和形参类型决定。
声明方式如下:
bool (*pf)(const string &,const string &);
注意pf两侧的括号不能少,不然就变成了单纯的返回值为指针类型的函数声明。
使用方式如下:
bool lengthCompare(const string &a,const string &b){ return a.size()<b.size();} //same as pf = &lengthCompare pf = lengthCompare; bool b1= pf("hello","fun"); cout<<b1<<endl; //这两个是等价的调用 bool b2 = (*pf)("hello","goodBye"); cout<<b2<<endl;
当然,函数指针也可以作为形参使用,用法如下:
void big(const string &a,const string &b, bool (*pf)(const string &,const string &)){//same as bool pf(const string &,const string &) cout<<pf(a,b)<<endl; }
如果嫌弃参数的表达式过于冗长,可以使用typedef定义类型。
typedef bool func(const string &,const string &);typedef bool (*funcP) (const string &,const string &);
因为在作为参数传递的时候,函数类型会被自动转换为指针,因此有以下两种用法。
void small(const string &a,const string &b,funcP fp){ bool res=fp(a,b); cout<<!res<<endl;}void smallTwo(const string &a,const string &b,func fp){ bool res=fp(a,b); cout<<!res<<endl;}
关于C++11的特性这里先不提及,有兴趣的可以查阅decltype与auto。完整的测试代码如下:
#include <iostream>#include <string>using namespace std;bool lengthCompare(const string &a,const string &b){ return a.size()<b.size();}bool (*pf)(const string &,const string &);typedef bool func(const string &,const string &);typedef bool (*funcP) (const string &,const string &);void big(const string &a,const string &b, bool (*pf)(const string &,const string &)){//same as bool pf(const string &,const string &) cout<<pf(a,b)<<endl; }void small(const string &a,const string &b,funcP fp){ bool res=fp(a,b); cout<<!res<<endl;}void smallTwo(const string &a,const string &b,func fp){ bool res=fp(a,b); cout<<!res<<endl;}int main(){ //same as pf = &lengthCompare pf = lengthCompare; bool b1= pf("hello","fun"); cout<<b1<<endl; bool b2 = (*pf)("hello","goodBye"); cout<<b2<<endl; big("hello","goodBye",lengthCompare); small("hello","goodBye",lengthCompare); smallTwo("hello","goodBye",lengthCompare); return 0;}
二、bind+function
bind和function是boost库中非常重要的部分,boost::function就像C#里的delegate,可以指向任何函数,包括成员函数。当用bind把某个成员函数绑到某个对象上时,我们得到了一个closure(闭包)。(陈硕语)
这里先介绍一下使用:
bind可以绑定函数,函数对象,以及指向对象成员函数的指针。
先看一下最基础的绑定函数,注意这里和STL中的bind1st等不同之处就在于可以使用多个参数。函数的参数不仅可以储存拷贝,也可以使用引用。
int g(int a,int b,int c){ return a+b+c; } int x=1,y=2,z=3; //bind with function cout<<boost::bind(g,_1,_2,_3)(1,2,3)<<endl; cout<<boost::bind(g,_3,_3,_3)(1,2,3)<<endl;
下面是函数对象的绑定:
默认的是绑定函数对象的拷贝,也可以使用ref来储存一个函数对象的引用,具体用法如下:
struct F{ int operator()(int a, int b) { return a - b; } bool operator()(long a, long b) { return a == b; }};struct F2{ int s; typedef void result_type; void operator()(int x) { s += x; }}; //bind with function objects F f; x=100; cout<<boost::bind<int>(f,_1,_1)(x)<<endl; //bind with function objects and store a ref F2 f2 = { 0 }; int a[] = { 1, 2, 3 }; std::for_each(a, a+3, bind(ref(f2), _1)); cout<<f2.s<<endl;
指向成员函数的指针不是函数对象,不支持operator()的重载,bind可以接受它们作为第一个参数,用法如下:
struct X{ bool f(int a){ cout<<"using bing pointers to members"<<endl; }}; //using bind with pointers to members X x1; shared_ptr<X> p(new X); int i = 5; boost::bind(&X::f, &x1, _1)(i); // (&x)->f(i) boost::bind(&X::f, x1, _1)(i); // (internal copy of x).f(i) boost::bind(&X::f, p, _1)(i); // (internal copy of p)->f(i)
前面介绍过,function使用返回类型和参数来完成类型函数模板的功能。什么如下:
boost::function<float (int x, int y)> f;
如果没有bind,function并没有什么特别用处,二者结合,就可以实现一种委托的功能。“同一个类的不同对象可以delegate给不同的实现,从而实现不同的行为”(myan语)。两者结合使用如下(陈硕的小例子):
#include <iostream>#include <boost/bind.hpp>#include <boost/function.hpp>#include <algorithm>#include <memory>using namespace std;void sum(int a,int b){ cout<<"sum is :"<<a+b<<endl;}class Foo{ public: void methodA(){ cout<<"methodA"<<endl; } void methodInt(int a){ cout<<"methodInt:"<<a<<endl; }};class Bar{ public: void methodB(){ cout<<"methodB"<<endl; }};int main(){ boost::function<void(int,int)> f; f=∑ f(3,4); boost::function<void()> f1; // 无参数,无返回值 Foo foo; f1 = boost::bind(&Foo::methodA, &foo); f1(); // 调用 foo.methodA(); Bar bar; f1 = boost::bind(&Bar::methodB, &bar); f1(); // 调用 bar.methodB(); f1 = boost::bind(&Foo::methodInt, &foo, 42); f1(); // 调用 foo.methodInt(42); boost::function<void(int)> f2; // int 参数,无返回值 f2 = boost::bind(&Foo::methodInt, &foo, _1); f2(53); // 调用 foo.methodInt(53);}
乍看起来,似乎这些用法和函数指针的用法没有什么差别,有点无端炫技的感觉,其实不然。虽然本质一样,但是对象可以携带状态,有自己的数据存储,这就大大提高了函数指针的可用性。
三、委托模式
委托模式又称作代理模式,在GOF的《设计模式:可复用面向对象软件的基础》一书中对代理模式是这样说的:为其他对象提供一种代理以控制对这个对象的访问。
如果使用过翻墙浏览器的,应该对代理这个词不陌生。代理就是代替你和外界做交互,这里为什么提到这个设计模式,因为从本质上讲,上面函数指针的用法就是通过一个Proxy这样的东西,将你所要处理的东西,或者请求转发给某个函数或者对象。
Proxy:
- 保存一个引用使得代理可以访问实体。若RealSubject和Subject的接口相同,Proxy会引用Subject,就相当于在代理类中保存一个Subject指针,该指针会指向RealSubject;
- 提供一个与Subject的接口相同的接口,这样代理就可以用来替代实体;
- 控制对实体的存取,并可能负责创建和删除它;
- 其它功能依赖于代理的类型,例如: 远程代理负责对请求及其参数进行编码,并向不同地址空间中的实体发送已编码的请求;
虚代理可以缓存实体的附加信息,以便延迟对它的访问;
保护代理检查调用者是否具有实现一个请求所必须的访问权限。
Subject:
定义RealSubject和Proxy的共用接口,这样就在任何使用RealSubject的地方都可以使用Proxy;
RealSubject:定义Proxy所代理的实体。
最简单的实现就是对上面类图的实现:
#include <iostream>using namespace std;#define SAFE_DELETE(p) if (p) { delete p; p = NULL;}class CSubject{public: CSubject(){}; virtual ~CSubject(){} virtual void Request() = 0;};class CRealSubject : public CSubject{public: CRealSubject(){} ~CRealSubject(){} void Request() { cout<<"CRealSubject Request"<<endl; }};class CProxy : public CSubject{public: CProxy() : m_pRealSubject(NULL){} ~CProxy() { SAFE_DELETE(m_pRealSubject); } void Request() { if (NULL == m_pRealSubject) { m_pRealSubject = new CRealSubject(); } cout<<"CProxy Request"<<endl; m_pRealSubject->Request(); }private: CRealSubject *m_pRealSubject;};int main(){ CSubject *pSubject = new CProxy(); pSubject->Request(); SAFE_DELETE(pSubject);}
更复杂的例子可以参考智能指针。
- C++委托实现(函数指针,function+bind,委托模式)
- C# 委托 C函数指针
- C函数指针和C#委托
- 模版函数指针,C++委托的实现
- 模版函数指针,C++委托的实现
- C++中用模板函数指针实现委托
- 模版函数指针,C++委托的实现
- 模版函数指针,C++委托的实现
- 模版函数指针,C++委托的实现
- Objective-C 委托模式
- 委托模式-- object-c
- Object-C委托模式
- [cocos2d-x]例如C++的成员函数指针实现委托、监听者模式
- [cocos2d-x]例如C++的成员函数指针实现委托、监听者模式
- 函数指针,function,bind, lambda
- [C++]实现委托模型
- [C++]实现委托模型
- [C++]实现委托模型
- 开始写Java项目
- 彻底解决Android 应用方法数不能超过65536的问题
- 4.重建二叉树(做第二遍时感觉仍有有难度,第三次做还是要看一下思路才行)
- 如何学习算法
- 开发工具:GitHub的使用
- C++委托实现(函数指针,function+bind,委托模式)
- Python3 nonlocal
- windows 8关闭小键盘
- hdu 1241 简单 搜索DFS (深搜)
- bzoj 1411: [ZJOI2009]硬币游戏 找规律
- LeetCode------Contains Duplicate
- tabLayout 和Viewpager 实现滑动
- 对于静态和非静态类的属性的理解
- Linux--图形界面与文本界面的切换