C++实现委托机制(二)
1.引言:
上一篇文章已经介绍了如何构建一个无参数无返回值的函数指针的委托,这篇文章将对上一文章所述委托进行扩展,使得可以注册任意函数指针,不过再讲篇内容之前先要介绍一下实现这个功能所需要了解的C++11的一个新特性———可变参数模板。
2.可变参数模板:
template
显然可以让设计出来的函数或是类有更大的复用性。因为有很多处理都是与“处理对象的个数”关系不大的,比如说打屏(printf),比如说比较大小(max,min),比如函数绑定子(bind,function要对应各种可能的函数就要能“任意”参数个数和类型)。如果不能对应任意个参数,那么就总会有人无法重用已有的实现,而不得不再重复地写一个自己需要的处理,而共通库的实现者为了尽可能地让自己写的类(函数)能复用在更多的场景,也不得不重复地写很多的代码或是用诡异的技巧,宏之类的去实现有限个“任意参数”的对应。
- template<typename ... Params> class MyClass;
- MyClass<int, string> a;
typename...
表示一个参数包,这样我们使用的时候,传入一个<int,string>那么int,string就会被打包入Params中。恩,你可以吧这个参数包看做一个参数的结构体,并且这个结构体的大小是动态的,并且是匿名的。恩,也就是说你无法使用Params[0]这样的语法去随机调用某个类型。听到这里,觉得是匿名的那应该怎么使用呢?答案是递归展开!!!我们先来看一个函数的例子,假如我想写一个Max函数求传入所有参数的最大值,这个参数支持(int,double,float),返回值为double.那么函数原型你觉得大概可能是这样子的:
- template<typename ...Params>
- double Max(Params... _params)
- {
- double Maxnum;
- //求解过程
- return Maxnum;
- }
- template<typename Head,typename ...Tail>
- double Max(Head first,Tail... rest)
- {
- double Maxnum;
- Maxnum = Max(rest...);
- if (Maxnum < first)
- Maxnum = first;
- return Maxnum;
- }
- template<typename Head>
- double Max(Head first)
- {
- return first;
- }
这样就有了一个递归出口了。好,我们结合以上的代码写成一个完整的程序,看下如何使用的:
- #include<iostream>
- using namespace std;
- template<typename Head, typename ...Tail>
- double Max(Head first, Tail... rest)
- {
- double Maxnum=0;
- Maxnum = Max(rest...);
- if (Maxnum < first)
- Maxnum = first;
- return Maxnum;
- }
- template<typename Head>
- double Max(Head first)
- {
- return first;
- }
- int main()
- {
- cout << Max(1, 3, 3.4, 5.1, 1.5);
- }
输出结果是: 5.1,同样的,模板类是通过私有继承来实现递归的。
- template<typename Head, typename... Tail>
- class tuple<Head, Tail...> : private tuple<Tail...>{
- Head head;
- public:
- /* implementation */
- };
- template<typename Head>
- class tuple<Head> {
- /* one-tuple implementation */
- };
以上可变参数的基本内容就讲完了,如果还有不懂的可以自行百度
3.任意参数个数、返回值任意的函数指针委托:
- template<typename ReturnType, typename ...ParamType>
- class IDelegate
- {
- public:
- IDelegate(){}
- virtual ~IDelegate(){}
- virtual bool isType(const std::type_info& _type) = 0;
- virtual ReturnType invoke(ParamType ... params) = 0;
- virtual bool compare(IDelegate<ReturnType, ParamType...> *_delegate) const = 0;
- };
这样,这个接口的invoke函数将会是根据你的函数类型来动态生成对应的模板了。
同样的,我们把剩下三个类按照如此进行改造:
- //StaticDelegate 普通函数的委托
- template<typename ReturnType, typename ...ParamType>
- class CStaticDelegate :
- public IDelegate<ReturnType, ParamType...>
- {
- public:
- typedef ReturnType(*Func)(ParamType...);
- CStaticDelegate(Func _func) : mFunc(_func) { }
- virtual bool isType(const std::type_info& _type) { return typeid(CStaticDelegate<ReturnType, ParamType...>) == _type; }
- virtual ReturnType invoke(ParamType ... params) { return mFunc(params...); }
- virtual bool compare(IDelegate<ReturnType, ParamType ...> *_delegate)const
- {
- if (0 == _delegate || !_delegate->isType(typeid(CStaticDelegate<ReturnType, ParamType ...>))) return false;
- CStaticDelegate<ReturnType, ParamType ...> * cast = static_cast<CStaticDelegate<ReturnType, ParamType ...>*>(_delegate);
- return cast->mFunc == mFunc;
- }
- virtual ~CStaticDelegate(){}
- private:
- Func mFunc;
- };
- //成员函数委托
- template<typename T, typename ReturnType, typename ...ParamType>
- class CMethodDelegate :
- public IDelegate<ReturnType, ParamType...>
- {
- public:
- typedef ReturnType(T::*Method)(ParamType...);
- CMethodDelegate(T * _object, Method _method) : mObject(_object), mMethod(_method) { }
- virtual bool isType(const std::type_info& _type) { return typeid(CMethodDelegate<T, ReturnType, ParamType...>) == _type; }
- virtual ReturnType invoke(ParamType...params)
- {
- (mObject->*mMethod)(params...);
- }
- virtual bool compare(IDelegate<ReturnType, ParamType...> *_delegate) const
- {
- if (0 == _delegate || !_delegate->isType(typeid(CMethodDelegate<ReturnType, ParamType...>))) return false;
- CMethodDelegate<ReturnType, ParamType...>* cast = static_cast<CMethodDelegate<ReturnType, ParamType...>*>(_delegate);
- return cast->mObject == mObject && cast->mMethod == mMethod;
- }
- CMethodDelegate(){}
- virtual ~CMethodDelegate(){}
- private:
- T * mObject;
- Method mMethod;
- };
- //多播委托
- template<typename ReturnType, typename ...ParamType>
- class CMultiDelegate
- {
- public:
- typedef std::list<IDelegate<ReturnType, ParamType...>*> ListDelegate;
- typedef typename ListDelegate::iterator ListDelegateIterator;
- typedef typename ListDelegate::const_iterator ConstListDelegateIterator;
- CMultiDelegate() { }
- ~CMultiDelegate() { clear(); }
- bool empty() const
- {
- for (ConstListDelegateIterator iter = mListDelegates.begin(); iter != mListDelegates.end(); ++iter)
- {
- if (*iter) return false;
- }
- return true;
- }
- void clear()
- {
- for (ListDelegateIterator iter = mListDelegates.begin(); iter != mListDelegates.end(); ++iter)
- {
- if (*iter)
- {
- delete (*iter);
- (*iter) = nullptr;
- }
- }
- }
- CMultiDelegate<ReturnType, ParamType...>& operator+=(IDelegate<ReturnType, ParamType...>* _delegate)
- {
- for (ListDelegateIterator iter = mListDelegates.begin(); iter != mListDelegates.end(); ++iter)
- {
- if ((*iter) && (*iter)->compare(_delegate))
- {
- delete _delegate;
- return *this;
- }
- }
- mListDelegates.push_back(_delegate);
- return *this;
- }
- CMultiDelegate<ReturnType, ParamType...>& operator-=(IDelegate<ReturnType, ParamType...>* _delegate)
- {
- for (ListDelegateIterator iter = mListDelegates.begin(); iter != mListDelegates.end(); ++iter)
- {
- if ((*iter) && (*iter)->compare(_delegate))
- {
- if ((*iter) != _delegate) delete (*iter); //避免同一个地址被delete两次
- (*iter) = 0;
- break;
- }
- }
- delete _delegate;
- return *this;
- }
- std::vector<ReturnType> operator()(ParamType... params)
- {
- ListDelegateIterator iter = mListDelegates.begin();
- std::vector<ReturnType> _Results;
- while (iter != mListDelegates.end())
- {
- if (0 == (*iter))
- {
- iter = mListDelegates.erase(iter);
- }
- else
- {
- _Results.push_back((*iter)->invoke(params...));
- ++iter;
- }
- }
- return _Results;
- }
- private:
- CMultiDelegate<ReturnType, ParamType...>(const CMultiDelegate& _event);
- CMultiDelegate<ReturnType, ParamType...>& operator=(const CMultiDelegate& _event);
- private:
- ListDelegate mListDelegates;
- };
但是这样写你会发现你在newDelegate里面对于传来的函数指针进行new
CStaticDelegate或者new
CMethodDelegate的时候需要制定函数返回值、参数的个数和类型,这显然不满足动态类型演化。这时候我们想,能不能给定一个函数指针,让代码自动去识别这个函数的返回值和参数呢?答案是可以的,我们只需要对上面的CStaticDelegate和CMethodDelegate特化一个版本即可。
- //普通函数的委托特化版本
- template<typename ReturnType, typename ...ParamType>
- class CStaticDelegate<ReturnType(*)(ParamType ...)> :
- public IDelegate<ReturnType, ParamType ...>
- {
- public:
- //定义 Func 为 void (void) 函数类型指针。
- typedef ReturnType(*Func)(ParamType...);
- CStaticDelegate(Func _func) : mFunc(_func) { }
- virtual bool isType(const std::type_info& _type) { return typeid(CStaticDelegate<ReturnType(*)(ParamType ...)>) == _type; }
- virtual ReturnType invoke(ParamType ... params) { return mFunc(params...); }
- virtual bool compare(IDelegate<ReturnType, ParamType ...> *_delegate)const
- {
- if (0 == _delegate || !_delegate->isType(typeid(CStaticDelegate<ReturnType(*)(ParamType ...)>))) return false;
- CStaticDelegate<ReturnType(*)(ParamType ...)> * cast = static_cast<CStaticDelegate<ReturnType(*)(ParamType ...)>*>(_delegate);
- return cast->mFunc == mFunc;
- }
- virtual ~CStaticDelegate(){}
- private:
- Func mFunc;
- };
- //成员函数委托特化
- template<typename T, typename ReturnType, typename ...ParamType>
- class CMethodDelegate<T,ReturnType (T:: *)(ParamType...)> :
- public IDelegate<ReturnType, ParamType...>
- {
- public:
- typedef ReturnType(T::*Method)(ParamType...);
- CMethodDelegate(T * _object, Method _method) : mObject(_object), mMethod(_method) { }
- virtual bool isType(const std::type_info& _type) { return typeid(CMethodDelegate<T,ReturnType(T:: *)(ParamType...)>) == _type; }
- virtual ReturnType invoke(ParamType...params)
- {
- return (mObject->*mMethod)(params...);
- }
- virtual bool compare(IDelegate<ReturnType, ParamType...> *_delegate) const
- {
- if (0 == _delegate || !_delegate->isType(typeid(CMethodDelegate<T, ReturnType(T:: *)(ParamType...)>))) return false;
- CMethodDelegate<T, ReturnType(T:: *)(ParamType...)>* cast = static_cast<CMethodDelegate<T, ReturnType(T:: *)(ParamType...)>*>(_delegate);
- return cast->mObject == mObject && cast->mMethod == mMethod;
- }
- CMethodDelegate(){}
- virtual ~CMethodDelegate(){}
- private:
- T * mObject;
- Method mMethod;
- };
这样我生成的时候只需要new CStaticDelegate<decltype(Func)>(Func),而特化版本的可以自动识别这个Func的返回值、参数个数和类型。
- template< typename T>
- CStaticDelegate<T>* newDelegate(T func)
- {
- return new CStaticDelegate<T>(func);
- }
- template< typename T,typename F>
- CMethodDelegate<T,F>* newDelegate(T * _object, F func)
- {
- return new CMethodDelegate<T, F>(_object, func);
- }
写到这里基本上可变参数的委托就完成了,不过还需要注意一点就是void无返回值类型多播委托需要特殊处理。所以我们还需要一个多播委托对于ReturnType为void这个情况的特化。
- template< typename ...ParamType>
- class CMultiDelegate<void, ParamType...>
- {
- public:
- typedef std::list<IDelegate<void, ParamType...>*> ListDelegate;
- typedef typename ListDelegate::iterator ListDelegateIterator;
- typedef typename ListDelegate::const_iterator ConstListDelegateIterator;
- CMultiDelegate() { }
- ~CMultiDelegate() { clear(); }
- bool empty() const
- {
- for (ConstListDelegateIterator iter = mListDelegates.begin(); iter != mListDelegates.end(); ++iter)
- {
- if (*iter) return false;
- }
- return true;
- }
- void clear()
- {
- for (ListDelegateIterator iter = mListDelegates.begin(); iter != mListDelegates.end(); ++iter)
- {
- if (*iter)
- {
- delete (*iter);
- (*iter) = nullptr;
- }
- }
- }
- CMultiDelegate<void, ParamType...>& operator+=(IDelegate<void, ParamType...>* _delegate)
- {
- for (ListDelegateIterator iter = mListDelegates.begin(); iter != mListDelegates.end(); ++iter)
- {
- if ((*iter) && (*iter)->compare(_delegate))
- {
- delete _delegate;
- return *this;
- }
- }
- mListDelegates.push_back(_delegate);
- return *this;
- }
- CMultiDelegate<void, ParamType...>& operator-=(IDelegate<void, ParamType...>* _delegate)
- {
- for (ListDelegateIterator iter = mListDelegates.begin(); iter != mListDelegates.end(); ++iter)
- {
- if ((*iter) && (*iter)->compare(_delegate))
- {
- if ((*iter) != _delegate) delete (*iter); //避免同一个地址被delete两次
- (*iter) = 0;
- break;
- }
- }
- delete _delegate;
- return *this;
- }
- void operator()(ParamType... params)
- {
- ListDelegateIterator iter = mListDelegates.begin();
- while (iter != mListDelegates.end())
- {
- if (0 == (*iter))
- {
- iter = mListDelegates.erase(iter);
- }
- else
- {
- (*iter)->invoke(params...);
- ++iter;
- }
- }
- }
- private:
- CMultiDelegate<void, ParamType...>(const CMultiDelegate& _event);
- CMultiDelegate<void, ParamType...>& operator=(const CMultiDelegate& _event);
- private:
- ListDelegate mListDelegates;
- };
所有代码都已经贴出来了,我把这些模板全部放到了MyDelegate.h头文件中。下面给一个使用的例子:
- #include "MyDelegate.h"
- using namespace Delegate;
- void NormalFunc(int a)
- {
- printf("这里是普通函数 :%d\n", a);
- }
- class A
- {
- public:
- static void StaticFunc(int a)
- {
- printf("这里是成员静态函数 : %d\n", a);
- }
- void MemberFunc(int a)
- {
- printf("这里是成员非静态函数 : %d\n", a);
- }
- };
- int _tmain(int argc, _TCHAR* argv[])
- {
- //首先创建了一个返回值为 void ,参数为int 的一个委托。
- CMultiDelegate<void, int> e;
- //将三个函数注册到该委托中
- e += newDelegate(NormalFunc);
- e += newDelegate(A::StaticFunc);
- e += newDelegate(&A(), &A::MemberFunc);
- //调用
- e(1);
- return 0;
- } <strong> </strong>
C++实现委托机制(二)的更多相关文章
- C++实现委托机制(一)
1.引言: 如果你接触过C#,你就会觉得C#中的delegate(委托)十分灵巧,它的用法上和C\C++的函数指针很像,但是却又比C\C++的函数指针更加灵活.并且委托可以一对多,也就是可以注册多个函 ...
- Javascript事件模型系列(二)事件的捕获-冒泡机制及事件委托机制
一.事件的捕获与冒泡 由W3C规定的DOM2标准中,一次事件的完整过程包括三步:捕获→执行目标元素的监听函数→冒泡,在捕获和冒泡阶段,会依次检查途径的每个节点,如果该节点注册了相应的监听函数,则执行监 ...
- 【Unity3D技巧】在Unity中使用事件/委托机制(event/delegate)进行GameObject之间的通信 (二) : 引入中间层NotificationCenter
作者:王选易,出处:http://www.cnblogs.com/neverdie/ 欢迎转载,也请保留这段声明.如果你喜欢这篇文章,请点[推荐].谢谢! 一对多的观察者模式机制有什么缺点? 想要查看 ...
- java类加载器学习2——自定义类加载器和父类委托机制带来的问题
一.自定义类加载器的一般步骤 Java的类加载器自从JDK1.2开始便引入了一条机制叫做父类委托机制.一个类需要被加载的时候,JVM先会调用他的父类加载器进行加载,父类调用父类的父类,一直到顶级类加载 ...
- JAVA基础|从Class.forName初始化数据库到SPI破坏双亲委托机制
代码托管在:https://github.com/fabe2ry/classloaderDemo 初始化数据库 如果你写过操作数据库的程序的话,可能会注意,有的代码会在程序的开头,有Class.for ...
- C++模拟C#事件委托机制(一)
原文来自于http://www.cnblogs.com/netssfy/articles/1652671.html 写了一段时间的C#代码后确实发现C#的事件委托非常好用.于是便想是否在C++中也能如 ...
- Java虚拟机JVM学习06 自定义类加载器 父委托机制和命名空间的再讨论
Java虚拟机JVM学习06 自定义类加载器 父委托机制和命名空间的再讨论 创建用户自定义的类加载器 要创建用户自定义的类加载器,只需要扩展java.lang.ClassLoader类,然后覆盖它的f ...
- Java虚拟机JVM学习05 类加载器的父委托机制
Java虚拟机JVM学习05 类加载器的父委托机制 类加载器 类加载器用来把类加载到Java虚拟机中. 类加载器的类型 有两种类型的类加载器: 1.JVM自带的加载器: 根类加载器(Bootstrap ...
- Invoke() 方法是 Unity3D 的一种委托机制
Invoke() 方法是 Unity3D 的一种委托机制 如: Invoke("SendMsg", 5); 它的意思是:5 秒之后调用 SendMsg() 方法: 使用 Inv ...
随机推荐
- LeetCode 16. 3Sum Closest(最接近的三数之和)
LeetCode 16. 3Sum Closest(最接近的三数之和)
- Python内置函数__slots__
''' 1.__slots__是什么:是一个类变量,变量值可以是列表,元祖,或者可迭代对象,也可以是一个字符串(意味着所有实例只有一个数据属性) 2.引子:使用点来访问属性本质就是在访问类或者对象的_ ...
- 11.6八校联考T1,T2题解
因为版权问题,不丢题面,不放代码了(出题人姓名也隐藏) T1 这,是一道,DP题,但是我最开始看的时候,我思路挂了,以为是一道简单题,然后就写错了 后来,我正确理解题意后写了个dfs,幸亏没有记忆化, ...
- HDU 6215 Brute Force Sorting(模拟链表 思维)
Brute Force Sorting Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 65535/32768 K (Java/Othe ...
- debug id
id是Eclipse的debugger自己生成的,用于告诉你哪些变量是指向同一个对象:id相同即指向同一个对象. primitive不是对象,所以就没有id. 但是如果你用primitive的wrap ...
- trie--- POJ 3764 The xor-longest Path
The xor-longest Path Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 5453 Accepted: 1 ...
- Mac下配置Idea的Maven
环境版本: Mac OS: 10.13.4 JDK: 1.8 Idea: 2018.3 Maven: 3.6.0 Maven 相关配置: Maven 下载: http://maven.apache.o ...
- Codeforces Round #348 (VK Cup 2016 Round 2, Div. 2 Edition) A. Little Artem and Presents 水题
A. Little Artem and Presents 题目连接: http://www.codeforces.com/contest/669/problem/A Description Littl ...
- Unity 的一些特性
using System; using UnityEngine; using UnityEditor; using UnityEngine.Serialization; using Random = ...
- 配置nginx虚拟目录配置文件支持tp的pathinfo
lnmp自带的包不好用, 经测试,在相应的conf文件加入这句话即可: location / { if (!-e $request_filename) { rewrite ^(.*)$ /index. ...