学MCD,用TypeList实现的Visitor

sevecol 2003-08-08 05:34:53
#include <map>
using namespace std;

#define TYPELIST_1(T) TypeList<T,NullType>
#define TYPELIST_2(T1,T2) TypeList<T1,TYPELIST_1(T2) >

class IObject;

typedef void (*ff)(IObject&);

class IDispatcher
{
protected:
map<int,ff> m_map;
public:
ff Do(int t)
{
map<int,ff>::iterator t_iterator=m_map.find(t);

if (t_iterator==m_map.end())
{
MessageBox(NULL,"no find","haha",MB_OK);
return NULL;
}
else
{
return t_iterator->second;
}
};
};
// 每个派生自IObject得m_value都是不同的,用于识别不同的类
class IObject
{
public:
int m_value;
IObject(int t):m_value(t){};
virtual ~IObject(){};

virtual void pp(){};
virtual void view(IDispatcher& dispatcher)
{
ff f=dispatcher.Do(m_value);

if (f)
f(*this);
};
};

class A:public IObject
{
public:
A():IObject(1){};
};

class B:public IObject
{
public:
B():IObject(2){};
};

class C:public IObject
{
public:
C():IObject(3){};
};

template<class T>
struct Type2Type
{
typedef T OriginalType;
};

class NullType;

template<class T,class U>
struct TypeList
{
typedef T Head;
typedef U Tail;
};

typedef TypeList<A,TypeList<B,NullType> > mytypelist;

template<class T>
class FUnit
{};

template<>
class FUnit<A>
{
public:
enum { m_value=1 };
static void DoSomething(IObject& object)
{
MessageBox(NULL,"A:DoSomething","ddd",MB_OK);
};
};

template<>
class FUnit<B>
{
public:
enum { m_value=2 };
static void DoSomething(IObject& object)
{
MessageBox(NULL,"B:DoSomething","ddd",MB_OK);
};
};

template<class TList,template<class> class Unit>
class GH;

template<class T1,class T2,template<class> class Unit>
class GH<TYPELIST_2(T1,T2),Unit>:public GH<T1,Unit>,public GH<T2,Unit>
{
};

//加这个是VS.2003的行为和MCD的有所不同
template<class YT,template<class> class Unit>
class GH<TYPELIST_1(YT,NullType),Unit>:public GH<YT,Unit>,public GH<NullType,Unit>
{
};

template<class YT,template<class> class Unit>
class GH:public Unit<YT>
{
};

template<template<class> class Unit>
class GH<NullType,Unit>
{
};

template<class TList,template<class> class Unit>
class MyDispatcher:public IDispatcher
{
public:
MyDispatcher()
{
DoInsert<TList>();
};

template<typename T>
void DoInsert()
{
pair<int,ff> t_pair(GH<T,Unit>::GH<T::Head,Unit>::m_value,GH<T,Unit>::GH<T::Head,Unit>::DoSomething);
m_map.insert(t_pair);

DoInsert<T::Tail>();
};

template<>
void DoInsert<NullType>()
{
};

//替换DoSomething可以单独和整体。
//..................
};
...全文
49 10 打赏 收藏 转发到动态 举报
写回复
用AI写文章
10 条回复
切换为时间正序
请发表友善的回复…
发表回复
sevecol 2003-08-12
  • 打赏
  • 举报
回复
打算使用类名来代替int作为类的标示符。
确实,使用了map作为分配器的保存,确实对于运行时的效率有所影响。使用vector就好多了。
短歌如风 2003-08-11
  • 打赏
  • 举报
回复

  同样道理,IDispatcher::m_map也应该是static member+virual method。
  如果你的类ID是自己定义的连续int类型,使用vector代替map,可以提高效率。只有无法确定将要处理的类的集合时才应该使用map,不过要注意,这时与真正的visitor pattern相比唯一的好处就是适应性强,而运行效率将会受到影响。
sevecol 2003-08-11
  • 打赏
  • 举报
回复
谢谢你的建议。
短歌如风 2003-08-10
  • 打赏
  • 举报
回复
确实用了TypeList,但……Visitor在哪呢?

这不是visitor pattern,而是Double Dispatcher的一种实现——其中一个Dispatch由多态完成。

我觉得map的第二个模板参数应该定义为void (IDispatcher::*ff)(IObject*),因为有可能有时处理过程需要知道IDispatcher的状态,这个不能使用静态方法了。

sevecol 2003-08-10
  • 打赏
  • 举报
回复
谢谢你的意见:-)

注册的函数类型确实为void (IDispatcher::*ff)(IObject*)比较好,自由度更加大些.

我是在中间加了一个分发器.

GH<TYPELIST_1(YT,NullType),Unit>就是Visitor Object.
我将Visitor Object注册到分发器内了.

这里没有用到*this来让编译器决定选择Visitor Object相应的函数,用基类的view的好处是派生类不需要再另外注意这个函数,只需要考虑注册的问题.
短歌如风 2003-08-10
  • 打赏
  • 举报
回复
昨天有事,还没写完。
既然m_value是用来标识类而不是对象的,把它作为对象的状态属性就不太合适了,应该作为虚函数:
class IObject
{
public:
virtual int get_class_id() const = 0;
};
为了方便,可以写一个模板形式的衍生类:
template <int _id>
class DerivedObject: public IObject
{
public:
const static int CLSID = _id;
int get_class_id() const;
};

template<int _id>
int DerivedObject<_id>::get_class_id()
{
return _id;
)

然后从这个类继承:
class A: public DerivedObject<1>
{
...
};

class B: public DerivedObject<2>
{
...
};

常量CLSID的定义是为了配合typelist在编译时确定class_id,如果再配合type trait技术会更好。如果你的编译器不支持这样的常量定义方法,可以改用stub enum方法。
使用时最好把处理函数(或方法)也定义成模板形式,这样便于在编译时直接用class_id找到对应的处理函数。

其时这种方法我也常用,我觉得与其说它是一种visitor模式,不如说它更接近Double Dispatcher的一种形式。不过我很少使用type list,因为对map的初始化其实是由IDispatcher的衍行类进行的,并且通常各不相同(否则我就使用更简单有效的visitor pattern了),所以type list对它的帮助并不大,徒然增加了代码的复杂程度。如果不是出于学习目的,我们不应该为了使用type list而使用它,而是一定是在需要使用时才使用。要记住:最简单的实现通常是最有效的。
sevecol 2003-08-10
  • 打赏
  • 举报
回复
上面的写错了
GH<TypeList,Unit>是Visitor Object
sevecol 2003-08-08
  • 打赏
  • 举报
回复
上面有些地方写错了
class GH<TYPELIST_2(T1,T2),Unit>:public GH<T1,Unit>,public GH<T2,Unit>
改成
class GH<TypeList<T1,T2>,Unit>:public GH<T1,Unit>,public GH<T2,Unit>

去掉那个我加的那个
//加这个是VS.2003的行为和MCD的有所不同
template<class YT,template<class> class Unit>
class GH<TYPELIST_1(YT,NullType),Unit>:public GH<YT,Unit>,public GH<NullType,Unit>
{
};

是我搞错了,行为是一样的。
sevecol 2003-08-08
  • 打赏
  • 举报
回复
还有就是MyDispatcher的替换实现函数对象的整体替换函数还没写。
sevecol 2003-08-08
  • 打赏
  • 举报
回复
大家多给点意见,谢谢。

24,854

社区成员

发帖
与我相关
我的任务
社区描述
C/C++ 工具平台和程序库
社区管理员
  • 工具平台和程序库社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧