前言
前几天在学习设计模式中的观察者模式时发现需要用到一个十分巧妙的机制——事件委托,事件委托的匿名属性,可以使得通知者对象更新观察者对象时不需要依赖具体名称的函数,是一种降低系统耦合度的设计。我看的设计模式书是《大话设计模式》,里面使用C#举例的,C#中就有事件委托的机制,而我是学C++,无奈C++中没有事件委托的设计,虽然Qt中有类似的机制——信号与槽,但是总感觉技术不如掌握在自己手中好,于是便搜索了不少资料,其中这篇资料给了我不少启发:
我顺着这章博客将代码敲了下来,里面存在一些小问题(可能是我和博主的编译器不同):模板参数无法转换。索性就自己重新编写了,顺便放到自己的仓库(仓库可能需要过几天才能弄好,所有的源码我放到了末尾)中:
学艺不精的安东/AntonaStandard (gitee.com)
我在原来博主的基础上,解决了模板参数无法转换的问题,另外添加了左值引用复制构造函数和右值引用移动构造函数,让整个项目更加完整。
实现
在网上查询了不少有关事件委托的信息,事件委托实际上就是将任意个同类型的函数交给一个对象(事件委托对象)来实现,可以想到如果要用C++来实现的话,肯定要用到函数指针。又因为非静态成员对象的调用依赖于具体的实例对象,为了能够以统一的方式存储这些函数指针就需要用多态进行封装,因此可以想到一下这种结构:
上面的图是用typora的mermaid插件绘制的,源码如下
classDiagram
class BaseFuncPointerContainer~type_RETURN_TYPE,type_PARAMETERS_TYPE...~{
+ abstract bool isType(const std::type_info& type)
+ abstract type_RETURN_VALUE call(type_PARAMETERS_PACK... para_args)
+ abstract bool equal(BaseFuncPointerContainer<type_RETURN_VALUE,type_PARAMETERS_PACK...>*container_ptr)
+ virtual BaseFuncPointerContainer* getSelf()
+ abstract BaseFuncPointerContainer* createNew(const BaseFuncPointerContainer<type_RETURN_VALUE,type_PARAMETERS_PACK...>& other)
}
class Static_NarmalFuncPointerContainer~type_RETURN_TYPE,type_PARAMETERS_TYPE...~{
# func_ptr :函数指针
+ override isType()
+ override call()
+ override equal()
+ override getSelf()
+ override createNew()
}
class MethodFuncPointerContainer~type_RETURN_TYPE,type_PARAMETERS_TYPE...~{
# func_ptr :函数指针
# obj_ptr :对象指针
+ override isType()
+ override call()
+ override equal()
+ override getSelf()
+ override createNew()
}
Static_NarmalFuncPointerContainer--|>BaseFuncPointerContainer
MethodFuncPointerContainer--|>BaseFuncPointerContainer
class Delegate~type_RETURN_TYPE,type_PARAMETERS_TYPE...~{
# list delegatelist
+ virtual clear()
+ virtual Delegate& operator+=()
+ virtual Delegate& operator-=()
+ virtual bool empty()
+ virtual unsigned long size()
}
Delegate o--> BaseFuncPointerContainer
首先设置一个抽象基类 BaseFuncPointerContainer 再由它派生出不同属性的函数指针的容器,其中由于普通函数的函数指针和静态成员函数的函数指针属性相同,都不依赖于具体的实例对象,因此它们可以用派生类 Static_NarmalFuncPointerContainer 存储,对于非静态成员函数来说它需要具体的实例对象来调用,因此需要保存实例对象的指针,通过MethodFuncPointerContainer 容器类来保存
BaseFuncPointerContainer中有公共的调用接口,因此创建一个委托类(Delegate)来保存所有添加进来的容器的指针(用标准模板库中的链表来存储),再通过公共的调用接口调用其中保存的函数指针。
不同参数列表的函数可以用C++11的新特性:可变模板参数来泛化存储
通过重载一个同名函数来隐藏不同派生类的创建(有一点简单工厂模式的味道,只不过我们这里没有创建工厂类)
以下是我在原文基础上修改的声明,解决了原先参数不匹配的问题,另外添加了由实例对象引用来创建容器的重载版本
// 返回普通函数或静态成员函数的重载版本
template<typename type_RETURN_VALUE, typename... type_PARAMETERS_PACK>
Static_NormalFuncPointerContainer<type_RETURN_VALUE,type_PARAMETERS_PACK...>*
newDelegate( type_RETURN_VALUE(*func_ptr)(type_PARAMETERS_PACK...) ){
return new Static_NormalFuncPointerContainer<type_RETURN_VALUE,type_PARAMETERS_PACK...>(func_ptr);
}
// 返回非静态成员函数容器的重载版本(由实例对象指针)
template<typename type_OBJECT,typename type_RETURN_VALUE,typename... type_PARAMETERS_PACK>
MethodFuncPointerContainer<type_OBJECT,type_RETURN_VALUE,type_PARAMETERS_PACK...>*
newDelegate(type_OBJECT* obj_ptr, type_RETURN_VALUE(type_OBJECT::*func_ptr)(type_PARAMETERS_PACK...)){
return new MethodFuncPointerContainer<type_OBJECT,type_RETURN_VALUE,type_PARAMETERS_PACK...>(obj_ptr,func_ptr);
}
// 由实例对象引用
template<typename type_OBJECT,typename type_RETURN_VALUE,typename... type_PARAMETERS_PACK>
MethodFuncPointerContainer<type_OBJECT,type_RETURN_VALUE,type_PARAMETERS_PACK...>*
newDelegate(type_OBJECT& obj, type_RETURN_VALUE(type_OBJECT::*func_ptr)(type_PARAMETERS_PACK...)){
return new MethodFuncPointerContainer<type_OBJECT,type_RETURN_VALUE,type_PARAMETERS_PACK...>(obj,func_ptr);
}
困难点
尝试编写复制构造函数的时候遇到了问题:由于委托类Delegate中存储的是抽象基类的指针,那么如何通过这个抽象基类的指针来构造出对应派生类型的指针容器呢?
我想到了可以用auto关键字在运行的阶段自动判断指针类型,但是如何获取这个指针本身的派生类型呢?
(2条消息) C++&Qt踩坑与经验总结_学艺不精的Антон的博客-CSDN博客
我想到了之前自己总结过的返回值协变问题,可以通过返回值协变来完成:
首先,不论是用派生类指针保存派生类对象,还是基类指针保存派生类对象,用这个指针访问虚函数,一定调用的是保存的实体的虚函数而不是基类的虚函数,然后返回值协变允许我们在重写一个返回值是基类指针或引用的虚函数时,用对应的派生类指针或引用替代基类指针或引用,并且仍然构成重写的操作,这样就可以通过基类指针调用该函数返回对应的派生类指针了
在BaseFuncPointerContainer中添加两个公有的虚函数
template<typename type_RETURN_VALUE, typename... type_PARAMETERS_PACK>
class BaseFuncPointerContainer{
public:
inline virtual BaseFuncPointerContainer* getSelf(){
// 返回一个类型样本(this指针),使得可以反向通过auto推断出其指针类型
return this;
}
inline virtual BaseFuncPointerContainer* createNew(const BaseFuncPointerContainer<type_RETURN_VALUE,type_PARAMETERS_PACK...>& other)=0;
};
在Static_NarmalFuncPointerContainer中重写:
template<typename type_RETURN_VALUE, typename... type_PARAMETERS_PACK>
class Static_NormalFuncPointerContainer:public BaseFuncPointerContainer<type_RETURN_VALUE,type_PARAMETERS_PACK...>{
public:
// 重写获取样本函数,返回值协变成派生类
inline virtual Static_NormalFuncPointerContainer* getSelf()override{
return this;
}
// 重写创建函数,返回值协变(不协变也可以)
inline virtual Static_NormalFuncPointerContainer* createNew(const BaseFuncPointerContainer<type_RETURN_VALUE,type_PARAMETERS_PACK...>& other)override{
const Static_NormalFuncPointerContainer& _other = static_cast<const Static_NormalFuncPointerContainer&>(other);
return new Static_NormalFuncPointerContainer(_other.func_ptr);
}
};
在MethodFuncPointerContainer中重写:
template<typename type_OBJECT,typename type_RETURN_VALUE,typename... type_PARAMETERS_PACK>
class MethodFuncPointerContainer:public BaseFuncPointerContainer<type_RETURN_VALUE,type_PARAMETERS_PACK...>{
public:
// 重写获取样本函数,返回值协变成派生类
inline virtual MethodFuncPointerContainer* getSelf()override{
return this;
}
// 重写创建函数,返回值协变(不协变也可以)
inline virtual MethodFuncPointerContainer* createNew(const BaseFuncPointerContainer<type_RETURN_VALUE,type_PARAMETERS_PACK...>& other)override{
const MethodFuncPointerContainer& _other = static_cast<const MethodFuncPointerContainer&>(other);
return new MethodFuncPointerContainer(_other.obj_ptr,_other.func_ptr);
}
然后在委托类中这样编写左值引用复制构造函数
// 左值引用复制构造函数
template<typename type_RETURN_VALUE, typename... type_PARAMETERS_PACK>
Delegate<type_RETURN_VALUE, type_PARAMETERS_PACK...>::
Delegate
(const Delegate<type_RETURN_VALUE, type_PARAMETERS_PACK...> &other){
// 注意,链表中存储的是函数指针的容器,所以需要我们遍历other分配内存
DelegateListConstIterator iter = other.delegateList.begin();
DelegateListConstIterator end = other.delegateList.end();
// 由于协变,基类指针隐藏了派生类的细节,那么如何获得当前类是哪种派生类:用虚函数和返回值协变
while(iter != end){
// 获取iter指向的容器派生类指针
auto container_ptr = (*iter)->getSelf();
// 调用对应派生类的createNew函数获得一个拷贝(拷贝存储的函数指针和原版一模一样)
container_ptr = container_ptr->createNew(**iter);
this->delegateList.push_back(container_ptr);
++iter;
}
}
给出所有的源码
NotFound_Error是我派生std::logic_error实现的
#ifndef DELEGATE_H
#define DELEGATE_H
#include <typeinfo>
#include <vector>
#include <list>
#include <stdexcept>
#include "Exception.h"
namespace AntonaStandard{
#define Delegate_VERSION "1.0.0"
#define Delegate_EDIT_TIME "2022/12/29"
#define Delegate_AUTHOR "Anton"
}
/*
* Decoded by utf-8
* 2022/12/19 1.0.0 初步实现事件委托,对于有返回值的函数,暂时采取其返回值弃用的操作
*/
// 前置声明:forward declaration
namespace AntonaStandard{
// 抽象基类,为不同类型指针的存储提供多态接口
template<typename type_RETURN_VALUE, typename... type_PARAMETERS_PACK>
class BaseFuncPointerContainer;
// 存储类非静态成员函数的函数指针的容器,由BaseFuncPointerContainer派生
template<typename type_OBJECT,typename type_RETURN_VALUE,typename... type_PARAMETERS_PACK>
class MethodFuncPointerContainer;
// 存储普通函数和静态成员函数指针的容器(普通函数和静态成员函数的指针属性相同),由BaseFuncPointerContainer派生
template<typename type_RETURN_VALUE, typename... type_PARAMETERS_PACK>
class Static_NormalFuncPointerContainer;
// 委托类,以聚合的方式多态存储保存函数指针的容器类
template<typename type_RETURN_VALUE, typename... type_PARAMETERS_PACK>
class Delegate;
// // 特殊委托类型,保存的函数指针返回值为void
// template<typename... type_PARAMETERS_PACK>
// class Delegate<void,type_PARAMETERS_PACK...>;
// 为指针容器创建提供统一接口
// 返回普通函数或静态成员函数的重载版本
template<typename type_RETURN_VALUE, typename... type_PARAMETERS_PACK>
Static_NormalFuncPointerContainer<type_RETURN_VALUE,type_PARAMETERS_PACK...>*
newDelegate( type_RETURN_VALUE(*func_ptr)(type_PARAMETERS_PACK...) ); // 注意指针类型的声明
// 返回非静态成员函数容器的重载版本
template<typename type_OBJECT,typename type_RETURN_VALUE,typename... type_PARAMETERS_PACK>
MethodFuncPointerContainer<type_OBJECT,type_RETURN_VALUE,type_PARAMETERS_PACK...>*
newDelegate(type_OBJECT* obj_ptr, type_RETURN_VALUE(type_OBJECT::*func_ptr)(type_PARAMETERS_PACK...));
template<typename type_OBJECT,typename type_RETURN_VALUE,typename... type_PARAMETERS_PACK>
MethodFuncPointerContainer<type_OBJECT,type_RETURN_VALUE,type_PARAMETERS_PACK...>*
newDelegate(type_OBJECT& obj_ptr, type_RETURN_VALUE(type_OBJECT::*func_ptr)(type_PARAMETERS_PACK...));
}
// 模板类声明: declaration of template class
namespace AntonaStandard{
// 抽象基类
template<typename type_RETURN_VALUE, typename... type_PARAMETERS_PACK>
class BaseFuncPointerContainer{
public:
BaseFuncPointerContainer(){};
// 声明虚析构函数
virtual ~BaseFuncPointerContainer(){};
// 判断传入的参数是否属于类型
virtual bool isType(const std::type_info& type)=0;
virtual type_RETURN_VALUE call(type_PARAMETERS_PACK... para_args)=0;
virtual bool equal(BaseFuncPointerContainer<type_RETURN_VALUE,type_PARAMETERS_PACK...>* container_ptr)const=0;
inline virtual BaseFuncPointerContainer* getSelf(){
// 返回一个类型样本(this指针),使得可以反向通过auto推断出其指针类型
return this;
}
inline virtual BaseFuncPointerContainer* createNew(const BaseFuncPointerContainer<type_RETURN_VALUE,type_PARAMETERS_PACK...>& other)=0;
};
// 保存非静态成员函数指针的容器
template<typename type_OBJECT,typename type_RETURN_VALUE,typename... type_PARAMETERS_PACK>
class MethodFuncPointerContainer:public BaseFuncPointerContainer<type_RETURN_VALUE,type_PARAMETERS_PACK...>{
public:
// 类型重命名(函数指针类型)
using FuncPtr_Type = type_RETURN_VALUE(type_OBJECT::*)(type_PARAMETERS_PACK...);
protected:
type_OBJECT* obj_ptr; // 对象指针
FuncPtr_Type func_ptr; // 非静态成员函数指针
public:
// 通过引用构造
MethodFuncPointerContainer(type_OBJECT& obj,FuncPtr_Type _func_ptr ):obj_ptr(&obj),func_ptr(_func_ptr){};
// 通过指针构造
MethodFuncPointerContainer(type_OBJECT* _obj_ptr,FuncPtr_Type _func_ptr):obj_ptr(_obj_ptr),func_ptr(_func_ptr){};
// 声明虚析构函数
virtual ~MethodFuncPointerContainer(){};
// 重写,判断传入的参数是否属于类型
virtual bool isType(const std::type_info& type)override;
// 重写,调用函数指针
virtual type_RETURN_VALUE call(type_PARAMETERS_PACK... para_args)override;
// 重写,判断两个函数指针及其实例对象是否相等
virtual bool equal(BaseFuncPointerContainer<type_RETURN_VALUE,type_PARAMETERS_PACK...>* container_ptr)const override;
// 重写获取样本函数,返回值协变成派生类
inline virtual MethodFuncPointerContainer* getSelf()override{
return this;
}
// 重写创建函数,返回值协变(不协变也可以)
inline virtual MethodFuncPointerContainer* createNew(const BaseFuncPointerContainer<type_RETURN_VALUE,type_PARAMETERS_PACK...>& other)override{
const MethodFuncPointerContainer& _other = static_cast<const MethodFuncPointerContainer&>(other);
return new MethodFuncPointerContainer(_other.obj_ptr,_other.func_ptr);
}
};
// 保存静态成员函数和普通函数的容器类
template<typename type_RETURN_VALUE, typename... type_PARAMETERS_PACK>
class Static_NormalFuncPointerContainer:public BaseFuncPointerContainer<type_RETURN_VALUE,type_PARAMETERS_PACK...>{
public:
using FuncPtr_Type = type_RETURN_VALUE(*)(type_PARAMETERS_PACK...);
protected:
FuncPtr_Type func_ptr;
public:
Static_NormalFuncPointerContainer(FuncPtr_Type _func_ptr ):func_ptr(_func_ptr){};
// 声明虚析构函数
virtual ~Static_NormalFuncPointerContainer(){};
// 重写,判断传入的参数是否属于类型
virtual bool isType(const std::type_info& type)override;
// 重写,调用函数指针
virtual type_RETURN_VALUE call(type_PARAMETERS_PACK... para_args)override;
// 重写,判断两个函数指针及其实例对象是否相等
virtual bool equal(BaseFuncPointerContainer<type_RETURN_VALUE,type_PARAMETERS_PACK...>* container_ptr)const override;
// 重写获取样本函数,返回值协变成派生类
inline virtual Static_NormalFuncPointerContainer* getSelf()override{
return this;
}
// 重写创建函数,返回值协变(不协变也可以)
inline virtual Static_NormalFuncPointerContainer* createNew(const BaseFuncPointerContainer<type_RETURN_VALUE,type_PARAMETERS_PACK...>& other)override{
const Static_NormalFuncPointerContainer& _other = static_cast<const Static_NormalFuncPointerContainer&>(other);
return new Static_NormalFuncPointerContainer(_other.func_ptr);
}
};
// 委托类
template<typename type_RETURN_VALUE, typename... type_PARAMETERS_PACK>
class Delegate{
// 通过链表存储容器
public:
// 声明一下链表和迭代器,化简表达
using DelegateList = std::list<BaseFuncPointerContainer<type_RETURN_VALUE,type_PARAMETERS_PACK...>* >;
using DelegateListIterator = typename DelegateList::iterator;
using DelegateListConstIterator = typename DelegateList::const_iterator;
protected:
DelegateList delegateList;
public:
// 声明为虚函数,提高可拓展性
// 获取委托个数
inline virtual unsigned long size()const{
return this->delegateList.size();
}
// 判断委托是否为空
inline virtual bool empty()const{
return this->delegateList.empty();
}
// 清空委托
virtual void clear();
virtual Delegate<type_RETURN_VALUE,type_PARAMETERS_PACK...>& operator+=(BaseFuncPointerContainer<type_RETURN_VALUE,type_PARAMETERS_PACK...>* other_ptr);
virtual Delegate<type_RETURN_VALUE,type_PARAMETERS_PACK...>& operator-=(BaseFuncPointerContainer<type_RETURN_VALUE,type_PARAMETERS_PACK...>* other_ptr);
// 暂时禁用多播返回值,因为如果type_RETURN_VALVE为一个引用类型的话std::vector无法进行存储
// virtual std::vector<type_RETURN_VALUE> operator()(type_PARAMETERS_PACK... parama_args);
virtual void operator()(type_PARAMETERS_PACK... parama_args);
// 左值赋值构造函数,和赋值函数
Delegate(const Delegate&);
Delegate<type_RETURN_VALUE,type_PARAMETERS_PACK...>& operator=(const Delegate<type_RETURN_VALUE,type_PARAMETERS_PACK...>&);
// 右值移动构造函数,和赋值函数
Delegate(Delegate&&);
Delegate<type_RETURN_VALUE,type_PARAMETERS_PACK...>& operator=(const Delegate<type_RETURN_VALUE,type_PARAMETERS_PACK...>&&);
// 空构造函数
Delegate(){};
// 虚析构函数
virtual ~Delegate(){this->clear();};
};
// // 特殊情况,返回值是空的委托类
// template<typename... type_PARAMETERS_PACK>
// class Delegate<void,type_PARAMETERS_PACK...>{
// // 通过链表存储容器
// public:
// // 声明一下链表和迭代器,化简表达
// using DelegateList = std::list<BaseFuncPointerContainer<void,type_PARAMETERS_PACK...>>;
// using DelegateListIterator = typename DelegateList::iterator;
// using DelegateListConstIterator = typename DelegateList::const_iterator;
// protected:
// DelegateList delegateList;
// public:
// // 声明为虚函数,提高可拓展性
// // 获取委托个数
// virtual unsigned long size()const;
// // 判断委托是否为空
// virtual bool empty()const;
// // 清空委托
// virtual void clear();
// // 删除委托,并返回当前委托的下一委托的迭代器
// virtual DelegateListIterator& erase(DelegateListIterator& iter);
// virtual Delegate<void,type_PARAMETERS_PACK...>& operator+=(BaseFuncPointerContainer<void,type_PARAMETERS_PACK...>* other_ptr);
// virtual Delegate<void,type_PARAMETERS_PACK...>& operator-=(BaseFuncPointerContainer<void,type_PARAMETERS_PACK...>* other_ptr);
// // 调用后不需要返回值
// virtual void operator()(type_PARAMETERS_PACK... parama_args);
// // 左值赋值构造函数,和赋值函数
// Delegate(const Delegate&);
// Delegate<void,type_PARAMETERS_PACK...>& operator=(const Delegate<void,type_PARAMETERS_PACK...>&);
// // 右值移动构造函数,和赋值函数
// Delegate(Delegate&&);
// Delegate<void,type_PARAMETERS_PACK...>& operator=(const Delegate<void,type_PARAMETERS_PACK...>&&);
// // 空构造函数
// Delegate(){};
// // 虚析构函数
// virtual ~Delegate(){this->clear();};
// };
}
// 相关函数定义
namespace AntonaStandard{
// 定义存储非静态成员函数的容器类
// 判断是否是同类型,用typeid进行比较
template<typename type_OBJECT,typename type_RETURN_VALUE,typename... type_PARAMETERS_PACK>
bool
MethodFuncPointerContainer<type_OBJECT,type_RETURN_VALUE,type_PARAMETERS_PACK...>::
isType
(const std::type_info& type){
return (typeid(MethodFuncPointerContainer<type_OBJECT,type_RETURN_VALUE,type_PARAMETERS_PACK...>)==type);
}
// 调用函数指针
template<typename type_OBJECT,typename type_RETURN_VALUE,typename... type_PARAMETERS_PACK>
type_RETURN_VALUE
MethodFuncPointerContainer<type_OBJECT,type_RETURN_VALUE,type_PARAMETERS_PACK...>::
call
(type_PARAMETERS_PACK... para_args){
return (this->obj_ptr->*(this->func_ptr))(para_args...);
}
// 判断实例对象和调用的函数指针是否相等
template<typename type_OBJECT,typename type_RETURN_VALUE,typename... type_PARAMETERS_PACK>
bool
MethodFuncPointerContainer<type_OBJECT,type_RETURN_VALUE,type_PARAMETERS_PACK...>::
equal
(BaseFuncPointerContainer<type_RETURN_VALUE,type_PARAMETERS_PACK...>* container_ptr)const {
if(container_ptr == nullptr){
return false;
}if (!container_ptr->isType(typeid(MethodFuncPointerContainer<type_OBJECT,type_RETURN_VALUE,type_PARAMETERS_PACK...>))){
// 判断container_ptr的类型是否与当前对象的类型相等
return false;
}
// 比较实例对象和函数指针的地址是否相同
MethodFuncPointerContainer<type_OBJECT,type_RETURN_VALUE,type_PARAMETERS_PACK...>* cast =
static_cast<MethodFuncPointerContainer<type_OBJECT,type_RETURN_VALUE,type_PARAMETERS_PACK...>*>(container_ptr);
return this->obj_ptr == cast->obj_ptr && this->func_ptr == cast->func_ptr;
}
// 静态成员函数指针和普通函数指针容器类的成员定义
template<typename type_RETURN_VALUE, typename... type_PARAMETERS_PACK>
bool
Static_NormalFuncPointerContainer<type_RETURN_VALUE, type_PARAMETERS_PACK...>::
isType
(const std::type_info &type){
return (typeid(Static_NormalFuncPointerContainer<type_RETURN_VALUE, type_PARAMETERS_PACK...>) == type);
}
template<typename type_RETURN_VALUE, typename... type_PARAMETERS_PACK>
type_RETURN_VALUE
Static_NormalFuncPointerContainer<type_RETURN_VALUE, type_PARAMETERS_PACK...>::
call(type_PARAMETERS_PACK... para_args){
return (*(this->func_ptr))(para_args...);
}
template<typename type_RETURN_VALUE, typename... type_PARAMETERS_PACK>
bool
Static_NormalFuncPointerContainer<type_RETURN_VALUE, type_PARAMETERS_PACK...>::
equal(BaseFuncPointerContainer<type_RETURN_VALUE,type_PARAMETERS_PACK...>* container_ptr)const{
if(container_ptr == nullptr){
return false;
}if (!container_ptr->isType(typeid(Static_NormalFuncPointerContainer<type_RETURN_VALUE, type_PARAMETERS_PACK...>))){
// 判断container_ptr的类型是否与当前对象的类型相等
return false;
}
// 比较函数指针的地址是否相同
Static_NormalFuncPointerContainer<type_RETURN_VALUE,type_PARAMETERS_PACK...>* cast =
static_cast<Static_NormalFuncPointerContainer<type_RETURN_VALUE,type_PARAMETERS_PACK...>*>(container_ptr);
return this->func_ptr == cast->func_ptr;
}
// 委托类
// 清理委托
template<typename type_RETURN_VALUE, typename... type_PARAMETERS_PACK>
void
Delegate<type_RETURN_VALUE, type_PARAMETERS_PACK...>::
clear(){
// 遍历链表,删除其中存储的容器指针
DelegateListIterator iter = this->delegateList.begin();
while(iter != this->delegateList.end()){
delete *iter; // 删除iter指向的内容(注意不是删除iter)
++iter;
}
// 调用链表的清除函数
this->delegateList.clear();
}
// += 运算符重载
template<typename type_RETURN_VALUE, typename... type_PARAMETERS_PACK>
Delegate<type_RETURN_VALUE,type_PARAMETERS_PACK...>&
Delegate<type_RETURN_VALUE,type_PARAMETERS_PACK...>::
operator+=
(BaseFuncPointerContainer<type_RETURN_VALUE,type_PARAMETERS_PACK...>* other_ptr){
// 接受容器指针(抽象基类指针,多态),遍历列表查看是否有重复的函数,有重复的就停止遍历否则插入在末尾
DelegateListIterator iter = this->delegateList.begin();
while(iter != this->delegateList.end()){
// 不同于参考代码(具体可以看我的博客)在删除委托(-=)是只是将链表结点中的指针清除了,我们这里通过erase同时清除了对应的结点,
// 因此保证每一个节点保存的容器指针一定不为空
// 清除了对应迭代器虽然会使得被清除的迭代器失效,但是所有的增删操作都封装在类中,不会出现再次使用被删除的迭代器的情况
if((*iter)->equal(other_ptr)){
// other_ptr是分配了内存的堆对象,需要删除
delete other_ptr;
other_ptr = nullptr; // 标记成nullptr,方便debug
return *this;
}
++iter;
}
// 循环正常结束,说明没有重复的函数指针,因此将other_ptr插入到链表的末尾
this->delegateList.push_back(other_ptr);
return *this;
}
// -= 运算符重载
template<typename type_RETURN_VALUE, typename... type_PARAMETERS_PACK>
Delegate<type_RETURN_VALUE,type_PARAMETERS_PACK...>&
Delegate<type_RETURN_VALUE,type_PARAMETERS_PACK...>::
operator-=
(BaseFuncPointerContainer<type_RETURN_VALUE,type_PARAMETERS_PACK...>* other_ptr){
// 依次比较函数指针,如果不存在抛出异常AntonaStandard::NotFound_Error
DelegateListIterator iter = this->delegateList.begin();
while(iter != this->delegateList.end()){
if((*iter)->equal(other_ptr)){
// 找到链表中与other_ptr保存的函数指针相等的容器,删除other_ptr和iter
delete other_ptr;
other_ptr = nullptr;
this->delegateList.erase(iter);
return *this;
}
++iter;
}
// 循环正常结束,说明没有重复的函数指针,要删除的函数指针未找到,抛出异常,由客户端进行解决
throw AntonaStandard::NotFound_Error("The function pointer was not found,fail to delete its container!");
}
// ()运算符,委托调用存储的函数
template<class type_RETURN_VALUE, class... type_PARAMETERS_PACK>
void
Delegate<type_RETURN_VALUE, type_PARAMETERS_PACK...>::
operator()
(type_PARAMETERS_PACK ...parama_args){
DelegateListIterator iter = this->delegateList.begin();
while(iter != this->delegateList.end()){
(*iter)->call(parama_args...);
++iter;
}
}
// 左值引用复制构造函数
template<typename type_RETURN_VALUE, typename... type_PARAMETERS_PACK>
Delegate<type_RETURN_VALUE, type_PARAMETERS_PACK...>::
Delegate
(const Delegate<type_RETURN_VALUE, type_PARAMETERS_PACK...> &other){
// 注意,链表中存储的是函数指针的容器,所以需要我们遍历other分配内存
DelegateListConstIterator iter = other.delegateList.begin();
DelegateListConstIterator end = other.delegateList.end();
// 由于协变,基类指针隐藏了派生类的细节,那么如何获得当前类是哪种派生类:用虚函数和返回值协变
while(iter != end){
auto container_ptr = (*iter)->getSelf();
container_ptr = container_ptr->createNew(**iter);
this->delegateList.push_back(container_ptr);
++iter;
}
}
// 左值引用赋值运算符
template<typename type_RETURN_VALUE, typename... type_PARAMETERS_PACK>
Delegate<type_RETURN_VALUE,type_PARAMETERS_PACK...> &
Delegate<type_RETURN_VALUE,type_PARAMETERS_PACK...>::
operator=
(const Delegate<type_RETURN_VALUE,type_PARAMETERS_PACK...> &other){
// 注意,链表中存储的是函数指针的容器,所以需要我们遍历other分配内存
DelegateListConstIterator iter = other.delegateList.begin();
DelegateListConstIterator end = other.delegateList.end();
// 由于协变,基类指针隐藏了派生类的细节,那么如何获得当前类是哪种派生类:用虚函数和返回值协变
while(iter != end){
// 推断指针类型
auto container_ptr = (*iter)->getSelf();
container_ptr = container_ptr->createNew(**iter);
this->delegateList.push_back(container_ptr);
++iter;
}
return *this;
}
// 右值引用移动构造函数
template<typename type_RETURN_VALUE, typename... type_PARAMETERS_PACK>
Delegate<type_RETURN_VALUE, type_PARAMETERS_PACK...>::
Delegate
(Delegate<type_RETURN_VALUE, type_PARAMETERS_PACK...>&& other){
// std::list有写好的右值赋值运算符,因此不需要我们做额外的操作
this->delegateList = std::move(other.delegateList);
}
// 右值引用赋值运算符
template<typename type_RETURN_VALUE, typename... type_PARAMETERS_PACK>
Delegate<type_RETURN_VALUE,type_PARAMETERS_PACK...> &
Delegate<type_RETURN_VALUE,type_PARAMETERS_PACK...>::
operator=
(const Delegate<type_RETURN_VALUE,type_PARAMETERS_PACK...>&& other){
this->delegateList = std::move(other.delegateList);
}
// 创建函数
// 为指针容器创建提供统一接口
// 返回普通函数或静态成员函数的重载版本
template<typename type_RETURN_VALUE, typename... type_PARAMETERS_PACK>
Static_NormalFuncPointerContainer<type_RETURN_VALUE,type_PARAMETERS_PACK...>*
newDelegate( type_RETURN_VALUE(*func_ptr)(type_PARAMETERS_PACK...) ){
return new Static_NormalFuncPointerContainer<type_RETURN_VALUE,type_PARAMETERS_PACK...>(func_ptr);
}
// 返回非静态成员函数容器的重载版本(由实例对象指针)
template<typename type_OBJECT,typename type_RETURN_VALUE,typename... type_PARAMETERS_PACK>
MethodFuncPointerContainer<type_OBJECT,type_RETURN_VALUE,type_PARAMETERS_PACK...>*
newDelegate(type_OBJECT* obj_ptr, type_RETURN_VALUE(type_OBJECT::*func_ptr)(type_PARAMETERS_PACK...)){
return new MethodFuncPointerContainer<type_OBJECT,type_RETURN_VALUE,type_PARAMETERS_PACK...>(obj_ptr,func_ptr);
}
// 由实例对象引用
template<typename type_OBJECT,typename type_RETURN_VALUE,typename... type_PARAMETERS_PACK>
MethodFuncPointerContainer<type_OBJECT,type_RETURN_VALUE,type_PARAMETERS_PACK...>*
newDelegate(type_OBJECT& obj, type_RETURN_VALUE(type_OBJECT::*func_ptr)(type_PARAMETERS_PACK...)){
return new MethodFuncPointerContainer<type_OBJECT,type_RETURN_VALUE,type_PARAMETERS_PACK...>(obj,func_ptr);
}
}
#endif
总结
经过两天的努力,解决了原文部分的问题,不过还有个问题让我十分恼火,就是事件委托到底应不应该保存返回值,想用C++实现有返回值的委托是有一定问题的,我们能想到的是,由委托类的重载运算符"()"来返回一个保存所有函数的返回值的线性表(std::vector),但是如果这些函数的返回值是类型引用的话就会出错,不管std::vector还是其它STL容器甚至数组,都是没有办法存储类型引用的,我没学过C#不知道C#是怎么解决的。另外目前来看,事件委托的返回值相当鸡肋,似乎没有什么用,难怪Qt的信号与槽都要求返回值为void (*д*)。
另外以上实现的事件委托不同于Qt的信号与槽,具有一定的局限性:线程不安全,也就是不能存储不同线程上的函数,因为可能发生冲突,而Qt的信号与槽可以解决不同线程上的通信问题,等过一段时间学完操作系统再尝试升升级。