zoukankan      html  css  js  c++  java
  • [置顶] 编程模仿boost::function和boost::bind

    boost::function和boost::bind结合使用是非常强大的,他可以将成员函数和非成员函数绑定对一个对象上,实现了类似C#的委托机制。委托在许多时候可以替代C++里面的继承,实现对象解耦,简单说就是把产生事件的代码和处理事件的代码通过委托者给隔离开来。

    但是boost库是非常庞大的,尤其是在发布开源软件时,下载安装boost是一件让用户望而却步的事情。基于此,下面编程模拟boost::function和boost::bind。

    为了满足90%以上的应用场合,该代码实现以下目标:

    1.支持成员函数和非成员函数绑定。

    2.支持多个参数(最多9个),代码中使用#define宏定义了1到9个参数的版本。

    3.为了在大规模应用中多次分配function对象造成内存碎片,对new和delete进行重载,方便使用内存池管理内存。


    下面贴出代码:

    /*
     *  Author:			chzuping
     *	Email:			chzuping@gmail.com
     *	description:	模拟boost::bind和boost::function
     */
    #pragma  once;
    #ifndef ZWBIND_MALLOC
    	#define ZWBIND_MALLOC malloc
    #endif
    #ifndef ZWBIND_FREE
    	#define ZWBIND_FREE free
    #endif
    namespace ZwBind
    {
    	class bind_base
    	{
    	public:
    		static void *operator new(size_t size )
    		{
    			return ZWBIND_MALLOC(size);
    		}
    		static void operator delete( void *ptr)
    		{
    			ZWBIND_FREE(ptr);
    		}
    	};
    	template<class ret_type>
    	class bind_base0:public bind_base
    	{
    	public:
    		virtual ret_type callfun() = 0;
    		ret_type operator()()
    		{
    			return callfun();
    		}
    	};
    	template<class ret_type, class obj_type>
    	class bindobj0 : public bind_base0<ret_type>
    	{
    	public:
    		bindobj0(obj_type* pobject, ret_type (obj_type::*pmemfun)())
    		{
    			m_pobject = pobject;
    			m_pmemfun = pmemfun;
    		}
    		virtual int callfun()
    		{
    			return (m_pobject->*m_pmemfun)();
    		}
    	private:
    		obj_type* m_pobject;
    		ret_type (obj_type::* m_pmemfun)();
    	};
    	template<class ret_type>
    	class bind0 : public bind_base0<ret_type>
    	{
    	public:
    		bind0( ret_type (*pfun)())
    		{
    			m_pfun = pfun;
    		}
    		virtual ret_type callfun()
    		{
    			return m_pfun();
    		}
    	private:
    		ret_type (*m_pfun)();
    	};
    	template<class ret_type, class obj_type>
    	bindobj0<ret_type,obj_type>* bindfun(obj_type* pclass, ret_type (obj_type::*pmemfun)())
    	{
    		void *pRet = NULL;
    		bindobj0<ret_type,obj_type>* pbind = new bindobj0<ret_type,obj_type>(pclass, pmemfun);
    		return pbind;
    	}
    	template<class ret_type>
    	bind0<ret_type>* bindfun(ret_type (*pmemfun)())
    	{
    		bind0<ret_type>* pbind = new bind0<ret_type>(pmemfun);
    		return pbind;
    	}
    #define DECLARE_PARAMS(...) __VA_ARGS__
    #define DECLARE_TPYE(...) __VA_ARGS__
    #define DECLARE_ARGS(...) __VA_ARGS__
    #define DECLARE_VAR(...) __VA_ARGS__
    
    #define  DECLARE_SIGSLOT(index, ptype,classparam,args,var) 
    template<class ret_type,classparam>
    class bind_base##index
    {
    public:
    	virtual ret_type callfun(args) = 0;
    	ret_type operator()(args)
    	{
    		return callfun(var);
    	}
    };
    template<class ret_type,class obj_type, classparam> 
    class bindobj##index:public bind_base##index<ret_type,ptype>
    {
    public:
    bindobj##index(obj_type* pobject, ret_type (obj_type::*pmemfun)(args))
    {
    	m_pobject = pobject;
    	m_pmemfun = pmemfun;
    }
    virtual ret_type callfun(args)
    {
    	return (m_pobject->*m_pmemfun)(var);
    }
    private:
    	obj_type* m_pobject;
    	ret_type (obj_type::* m_pmemfun)(args);
    };
    template<class ret_type,classparam>
    class bind##index : public bind_base##index<ret_type,ptype>
    {
    public:
    bind##index(ret_type (*pfun)(args))
    {
    	m_pfun = pfun;
    }
    virtual ret_type callfun(args)
    {
    	return m_pfun(var);
    }
    private:
    	ret_type (*m_pfun)(args);
    };
    template<class ret_type,class obj_type, classparam> 
    bindobj##index<ret_type,obj_type,ptype>* bindfun(obj_type* pclass, ret_type (obj_type::*pmemfun)(args))
    {
    	void *pRet = NULL;
    	bindobj##index<ret_type,obj_type,ptype>* pbind = new bindobj##index<ret_type,obj_type,ptype>(pclass, pmemfun);
    	return pbind;
    }
    template<class ret_type,classparam>
    bind##index<ret_type,ptype>* bindfun(ret_type (*pmemfun)(args))
    {
    	bind##index<ret_type,ptype>* pbind = new bind##index<ret_type,ptype>(pmemfun);
    	return pbind;
    }
    
    DECLARE_SIGSLOT(1,DECLARE_PARAMS(arg1_type), DECLARE_TPYE(class arg1_type),DECLARE_ARGS(arg1_type a1),DECLARE_VAR(a1));
    DECLARE_SIGSLOT(2,DECLARE_PARAMS(arg1_type,arg2_type), DECLARE_TPYE(class arg1_type,class arg2_type),DECLARE_ARGS(arg1_type a1, arg2_type a2),DECLARE_VAR( a1,  a2));
    DECLARE_SIGSLOT(3,DECLARE_PARAMS(arg1_type,arg2_type,arg3_type), DECLARE_TPYE(class arg1_type,class arg2_type,class arg3_type),DECLARE_ARGS(arg1_type a1, arg2_type a2, arg3_type a3),DECLARE_VAR( a1,a2,a3));
    DECLARE_SIGSLOT(4,DECLARE_PARAMS(arg1_type,arg2_type,arg3_type,arg4_type), DECLARE_TPYE(class arg1_type,class arg2_type,class arg3_type,class arg4_type),DECLARE_ARGS(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4),DECLARE_VAR( a1,a2,a3,a4));
    DECLARE_SIGSLOT(5,DECLARE_PARAMS(arg1_type,arg2_type,arg3_type,arg4_type,arg5_type), DECLARE_TPYE(class arg1_type,class arg2_type,class arg3_type,class arg4_type,class arg5_type),DECLARE_ARGS(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, arg5_type a5),DECLARE_VAR( a1,a2,a3,a4,a5));
    DECLARE_SIGSLOT(6,DECLARE_PARAMS(arg1_type,arg2_type,arg3_type,arg4_type,arg5_type,arg6_type), DECLARE_TPYE(class arg1_type,class arg2_type,class arg3_type,class arg4_type,class arg5_type,class arg6_type),DECLARE_ARGS(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, arg5_type a5, arg6_type a6),DECLARE_VAR( a1,a2,a3,a4,a5,a6));
    DECLARE_SIGSLOT(7,DECLARE_PARAMS(arg1_type,arg2_type,arg3_type,arg4_type,arg5_type,arg6_type,arg7_type), DECLARE_TPYE(class arg1_type,class arg2_type,class arg3_type,class arg4_type,class arg5_type,class arg6_type,class arg7_type),DECLARE_ARGS(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, arg5_type a5, arg6_type a6, arg7_type a7),DECLARE_VAR( a1,a2,a3,a4,a5,a6,a7));
    DECLARE_SIGSLOT(8,DECLARE_PARAMS(arg1_type,arg2_type,arg3_type,arg4_type,arg5_type,arg6_type,arg7_type,arg8_type), DECLARE_TPYE(class arg1_type,class arg2_type,class arg3_type,class arg4_type,class arg5_type,class arg6_type,class arg7_type,class arg8_type),DECLARE_ARGS(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, arg5_type a5, arg6_type a6, arg7_type a7, arg8_type a8),DECLARE_VAR( a1,a2,a3,a4,a5,a6,a7,a8));
    DECLARE_SIGSLOT(9,DECLARE_PARAMS(arg1_type,arg2_type,arg3_type,arg4_type,arg5_type,arg6_type,arg7_type,arg8_type,arg9_type), DECLARE_TPYE(class arg1_type,class arg2_type,class arg3_type,class arg4_type,class arg5_type,class arg6_type,class arg7_type,class arg8_type,class arg9_type),DECLARE_ARGS(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, arg5_type a5, arg6_type a6, arg7_type a7, arg8_type a8, arg9_type a9),DECLARE_VAR( a1,a2,a3,a4,a5,a6,a7,a8,a9));
    
    };
    using namespace ZwBind;


    在下面测试代码中,对0到3个参数的bind进行测试:

    #include "stdafx.h"
    #include <malloc.h>
    #include "ZwBind.h"
    
    int test0()
    {
    	printf("test0
    ");
    	return 0;
    }
    int test1(int a )
    {
    	printf("test1
    ");
    	return 0;
    }
    int test2(int ,char)
    {
    	printf("test2
    ");
    	return 0;
    }
    int test3(int ,char,short)
    {
    	printf("test3
    ");
    	return 0;
    }
    class TestClass
    {
    public:
    	int test0()
    	{
    		printf("test obj0
    ");
    		return 0;
    	}
    	int test1(int a )
    	{
    		printf("test obj1
    ");
    		return 0;
    	}
    	int test2(int ,char)
    	{
    		printf("test obj2
    ");
    		return 0;
    	}
    	int test3(int ,char,short)
    	{
    		printf("test obj3
    ");
    		return 0;
    	}
    };
    
    int _tmain(int argc, _TCHAR* argv[])
    {
    	TestClass TestObj;
    
    	//0个参数测试
    	printf("0 para test:
    ");
    	bind_base0<int>* t0 = bindfun(test0);
    	bind_base0<int>* tobj0 = bindfun(&TestObj,&TestClass::test0);
    	(*t0)();
    	(*tobj0)();
    	delete t0;
    	delete tobj0;
    	printf("
    ");
    
    	//1个参数测试
    	printf("1 para test:
    ");
    	bind_base1<int,int>* t1 = bindfun(test1);
    	bind_base1<int,int>* tobj1 = bindfun(&TestObj,&TestClass::test1);
    	(*t1)(12);
    	(*tobj1)(34);
    	delete t1;
    	delete tobj1;
    	printf("
    ");
    
    	//2个参数测试
    	printf("2 para test:
    ");
    	bind_base2<int,int,char>* t2 = bindfun(test2);
    	bind_base2<int,int,char>* tobj2 = bindfun(&TestObj,&TestClass::test2);
    	(*t2)(12,77);
    	(*tobj2)(34,55);
    	delete t2;
    	delete tobj2;
    	printf("
    ");
    
    	//3个参数测试
    	printf("3 para test:
    ");
    	bind_base3<int,int,char,short>* t3 = bindfun(test3);
    	bind_base3<int,int,char,short>* tobj3 = bindfun(&TestObj,&TestClass::test3);
    	(*t3)(12,77,56);
    	(*tobj3)(34,55,56);
    	delete t3;
    	delete tobj3;
    	printf("
    ");
    
    	return 0;
    }


    测试程序输出结果如下:



  • 相关阅读:
    使用tcmalloc编译启动时宕机
    使用tcmalloc编译出现undefined reference to `sem_init'
    使用AddressSanitizer做内存分析(一)——入门篇
    VIM-美化你的标签栏
    Entity Framework Code First (六)存储过程
    Entity Framework Code First (五)Fluent API
    Entity Framework Code First (四)Fluent API
    Entity Framework Code First (三)Data Annotations
    Entity Framework Code First (二)Custom Conventions
    Entity Framework Code First (一)Conventions
  • 原文地址:https://www.cnblogs.com/keanuyaoo/p/3318185.html
Copyright © 2011-2022 走看看