撤销和重做(Undo和Redo)的C++完美实现(7-B)

#if 0

在这一章里面将会讲解如何派生上一章里面所讲解的复合类,生成自己特殊的复合类
。生成这种特殊的复合类的派生类的目的就是为了方便使用者能够方便的添加自己的操作
,同时也是为了生成相应的类型。实际上需要对前一篇文章里面的的compound类进行修改
,参见代码CODE1:

#endif
#ifdef CODE1
#include <iostream>
#include "command.h"
#include "center.h"

//复合对象类的实现
#include "meta.h"//模板元编程基础与应用讨论的内容
#include "identifier.h"//复合对象类必须使用这个类
namespace pandaxcl{
//scatter产生代码需要的基元模板,用来生成属性
template <class T> struct compound_unit
{
identifier<T> ID;//属性对象的标识号
};
//利用scatter来生成代码创建自动化类,并通过模板元编程来实现操作代码的自动化
//这样之后这整个类就成了名副其实的自动化类了:)
template<class Cons>class compound
:public scatter<Cons,pandaxcl::compound_unit>
{
public:
typedef Cons cons_type;
typedef scatter<Cons,pandaxcl::compound_unit> scatter_type;

//特别注意下面的这些静态函数里面利用CID的object_type是为了使得
//这里的compound可以处理派身类,同时还不改变调用接口。

//复合对象的创建函数的自动化实现
template <class ControlType,class CID>
static void create(ControlType&C,const CID&ID,const typename CID::object_type&OC)
{
typedef typename CID::object_type object_type;
typedef container<CID,object_type> TCT;//复合对象容器类型
//CompoundType tmp;//定义一个临时的复合类对象
C.record();
//自动化创建所有的子图元
ENVIRONMENT<object_type,ControlType> e(C,OC);
LOOP<CREATE,0,length<cons_type>::value,1>::execute(e);
//然后创建自身,由于create命令和这里的create函数同名,所以
//用名字空间进行限制选择create命令
C.execute(new pandaxcl::create<TCT>(C,ID,OC));
C.stop();
}
//下面的函数是用来修改复合对象的属性的修改函数
template <size_t i,class PropertyType,class ControlType,class CID>
static void modify(ControlType&C,const CID&ID,const PropertyType&OM)
{
typedef typename CID::object_type object_type;
typedef container<CID,object_type> TCT;//复合对象容器类型
typedef identifier<PropertyType> PID;//属性对象使用的标识符类型
typedef container<PID,PropertyType> PCT;//属性对象使用的容器类型
typedef compound_unit<PropertyType> UTT;//确保每行代码不至于过长
const object_type &S = static_cast<TCT&>(C).reference(ID);
const UTT &P = static_cast<const UTT&>(field<i>(S));
//由于modify命令和这里的midify函数同名,所以用名字空间
//进行限制选择modify命令
C.execute(new pandaxcl::modify<PCT>(C,P.ID,OM));
}
//复合对象的删除函数的自动化实现
template <class ControlType,class CID>
static void remove(ControlType&C,const CID&ID)
{
typedef typename CID::object_type object_type;
//因为删除复合对象是一步操作,所以需要将所有的子元素的删除合并
//成为一个复合命令,使之表现的比较象简单对象的删除操作一样。
typedef container<CID,object_type> TCT;//复合对象容器类型
const object_type&S = static_cast<TCT&>(C).reference(ID);
C.record();
//自动化删除所有的子图元
ENVIRONMENT<object_type,ControlType> e(C,S);
LOOP<REMOVE,0,length<cons_type>::value,1>::execute(e);
//然后删除自身,由于remove命令和这里的remove函数同名,所以
//用名字空间进行限制选择remove命令
C.execute(new pandaxcl::remove<TCT>(C,ID));
C.stop();
}
private:
//CREATE和REMOVE都需要传入的动态参数结构
template<class CompoundType,class ControlType> struct ENVIRONMENT
{
typedef CompoundType compound_type;
typedef ControlType control_type;
ENVIRONMENT(ControlType&C,const CompoundType&c)
:_control(C),_compound(c){}
ControlType &_control;//控制面板
const CompoundType &_compound;//复合对象
};
//自动化的创建所有的属性对象
template<size_t i> struct CREATE
{
template<class EnvironmentType>
static void execute(EnvironmentType&e)
{
//你的代码在这里编写
typedef typename type<cons_type,i>::result CT;
typedef identifier<CT> PID;//属性对象使用的标识符类型
typedef container<PID,CT> PCT;//属性对象使用的容器类型
typedef compound_unit<CT> UTT;//确保每行代码不至于过长
const UTT &v = static_cast<const UTT&>(field<i>(e._compound));
typename EnvironmentType::control_type &C=e._control;
C.execute(new pandaxcl::create<PCT>(C,v.ID,CT()));
}
};
//自动化的删除所有的属性对象
template<size_t i> struct REMOVE
{
template<class EnvironmentType>
static void execute(EnvironmentType&e)
{
//你的代码在这里编写
typedef typename type<cons_type,i>::result CT;
typedef identifier<CT> PID;//属性对象使用的标识符类型
typedef container<PID,CT> PCT;//属性对象使用的容器类型
typedef compound_unit<CT> UTT;//确保每行代码不至于过长
const UTT &v = static_cast<const UTT&>(field<i>(e._compound));
typename EnvironmentType::control_type &C=e._control;
C.execute(new pandaxcl::remove<PCT>(C,v.ID));
}
};
};
}//namespace pandaxcl{

//下面的测试代码和前一章的类似,但是是采用上面的派生复合类模板来自动化的实现前面的
//RoundRectangle类!使用这种方法还可以用来给你的复合类添加额外的成员函数。不过需要
//注意的是,千万不要添加成员变量,因为成员变量完全可以以属性的形式添加。如果在派生
//的复合类中添加了成员变量,那么这个成员变量就不可以参与撤销和重做的管理机制了:)
namespace xcl = pandaxcl;//名字空间重命名
//矩形类
class Rectangle
{
public:
Rectangle():_x(0),_y(0),_width(20),_height(10){}
Rectangle(int x,int y,int w,int h):_x(x),_y(y),_width(w),_height(h){}
private:
int _x,_y,_width,_height;
//下面的函数仅仅是为了输出信息而准备的
friend std::ostream&operator<<(std::ostream&s,Rectangle&o)
{
s << "(" << o._x << "," << o._y << "," << o._width << "," << o._height << ")" ;
return s;
}
};
//圆形类
class Circle
{
public:
Circle():_x(0),_y(0),_radius(20){}
Circle(int x,int y,int r):_x(x),_y(y),_radius(r){}
private:
int _x,_y,_radius;
//下面的函数仅仅是为了输出信息而准备的
friend std::ostream&operator<<(std::ostream&s,Circle&o)
{
s << "(" << o._x << "," << o._y << "," << o._radius << ")" ;
return s;
}
};
//圆角矩形类
typedef xcl::cons<Rectangle,
xcl::cons<Circle,//重复类型
xcl::cons<Circle,//重复类型
xcl::cons<Circle,//重复类型
xcl::cons<Circle,//重复类型
xcl::null_type> > > > >ROUNDRECTANGLE;
//由上面的类型串自动生成圆角矩形类
class RoundRectangle : public xcl::compound<ROUNDRECTANGLE>
{
//在这里添加你的成员函数。
//下面的函数仅仅是为了输出信息而准备的,实际上下面的这个函数也是可以实现
//自动化的,不过这里为了简单起见,特殊情况特殊对待了:)。
friend std::ostream&operator<<(std::ostream&s,RoundRectangle&o)
{
s << "R:[" << std::hex << xcl::field<0>(o).ID << "] " ;
s << "C:[" << std::hex << xcl::field<1>(o).ID << "] " ;
s << "C:[" << std::hex << xcl::field<2>(o).ID << "] " ;
s << "C:[" << std::hex << xcl::field<3>(o).ID << "] " ;
s << "C:[" << std::hex << xcl::field<4>(o).ID << "] " ;
return s;
}
};
//在这里同样采用标识符模板的默认表示元素类型
typedef xcl::identifier<Rectangle > RID;//矩形类标识号类型
typedef xcl::identifier<Circle > CID;//圆形类标识号类型
typedef xcl::identifier<RoundRectangle> RRID;//圆角矩形类标识号类型
//观察容器的内容而准备的
template <class Container>
void display(const char*str,Container&c)
{
typedef typename Container::value_type value_type;
struct X
{
static void print(value_type&v)
{
std::cout.setf(std::ios::showbase);//显示16进制的0x前缀
std::cout << "(" <<std::hex<< v.first << "," ;
std::cout << std::dec << v.second << ") ";
}
};
//输出提示信息,并输出容器中的元素数量
std::cout << str << "[" << std::dec << c.size() << "] ";
std::for_each(c.begin(),c.end(),X::print);//输出容器中的所有的标识号和对象信息
std::cout << std::endl;
}

//需要一个控制面板类,实际上下面的这个类也是可以自动化的,不过这是后话:)
class Control
:public xcl::center
,public xcl::container<RID ,Rectangle >
,public xcl::container<CID ,Circle >
,public xcl::container<RRID,RoundRectangle>
{
public:
//下面的函数是输出该控制面板对象的相关信息的
void display(const char*str)
{
typedef xcl::container<RID ,Rectangle > RC;
typedef xcl::container<CID ,Circle > CC;
typedef xcl::container<RRID,RoundRectangle> RRC;
std::cout << "----------"<<str<<"----------" <<std::endl;
std::cout << "Undo:[" << std::dec << xcl::center::undo_type::size() << "] " ;
std::cout << "Redo:[" << std::dec << xcl::center::redo_type::size() << "] " ;
std::cout << std::endl ;
::display("矩形容器 :",static_cast<RC&>(*this));
::display("圆形容器 :",static_cast<CC&>(*this));
::display("圆角矩形容器:",static_cast<RRC&>(*this));
std::cout << "=========="<<str<<"==========" <<std::endl;
}
};
int main()
{
//首先应用程序中必须有一个全局的控制面板类对象
Control C;
RRID ID;//复合对象的标识号对象
//模拟创建复合对象
RoundRectangle::create(C,ID,RoundRectangle());
C.display("创建复合对象");
C.undo();//撤销一步
C.display("撤销一步");
C.redo();//重做一步
C.display("重做一步");
//模拟修改复合对象
C.record();
RoundRectangle::modify<0>(C,ID,Rectangle(1,1,200,100));
RoundRectangle::modify<1>(C,ID,Circle(1 ,1 ,5));
RoundRectangle::modify<2>(C,ID,Circle(201,1 ,5));
RoundRectangle::modify<3>(C,ID,Circle(201,101,5));
RoundRectangle::modify<4>(C,ID,Circle(1 ,101,5));
C.stop();
C.display("修改复合对象的属性");
C.undo();//撤销一步
C.display("撤销一步");
C.redo();//重做一步
C.display("重做一步");
//模拟删除复合对象
RoundRectangle::remove(C,ID);
C.display("删除复合对象");
C.undo();//撤销一步
C.display("撤销一步");
C.redo();//重做一步
C.display("重做一步");
return 0;
}
#endif//CODE1

//该程序运行结果如下:
/*******************************************************************************
----------创建复合对象----------
Undo:[1] Redo:[0]
矩形容器 :[1] (0x1,(0,0,20,10))
圆形容器 :[4] (0x1,(0,0,20)) (0x2,(0,0,20)) (0x3,(0,0,20)) (0x4,(0,0,20))
圆角矩形容器:[1] (0x1,R:[0x1] C:[0x1] C:[0x2] C:[0x3] C:[0x4] )
==========创建复合对象==========
----------撤销一步----------
Undo:[0] Redo:[1]
矩形容器 :[0]
圆形容器 :[0]
圆角矩形容器:[0]
==========撤销一步==========
----------重做一步----------
Undo:[1] Redo:[0]
矩形容器 :[1] (0x1,(0,0,20,10))
圆形容器 :[4] (0x1,(0,0,20)) (0x2,(0,0,20)) (0x3,(0,0,20)) (0x4,(0,0,20))
圆角矩形容器:[1] (0x1,R:[0x1] C:[0x1] C:[0x2] C:[0x3] C:[0x4] )
==========重做一步==========
----------修改复合对象的属性----------
Undo:[2] Redo:[0]
矩形容器 :[1] (0x1,(1,1,200,100))
圆形容器 :[4] (0x1,(1,1,5)) (0x2,(201,1,5)) (0x3,(201,101,5)) (0x4,(1,101,5))
圆角矩形容器:[1] (0x1,R:[0x1] C:[0x1] C:[0x2] C:[0x3] C:[0x4] )
==========修改复合对象的属性==========
----------撤销一步----------
Undo:[1] Redo:[1]
矩形容器 :[1] (0x1,(0,0,20,10))
圆形容器 :[4] (0x1,(0,0,20)) (0x2,(0,0,20)) (0x3,(0,0,20)) (0x4,(0,0,20))
圆角矩形容器:[1] (0x1,R:[0x1] C:[0x1] C:[0x2] C:[0x3] C:[0x4] )
==========撤销一步==========
----------重做一步----------
Undo:[2] Redo:[0]
矩形容器 :[1] (0x1,(1,1,200,100))
圆形容器 :[4] (0x1,(1,1,5)) (0x2,(201,1,5)) (0x3,(201,101,5)) (0x4,(1,101,5))
圆角矩形容器:[1] (0x1,R:[0x1] C:[0x1] C:[0x2] C:[0x3] C:[0x4] )
==========重做一步==========
----------删除复合对象----------
Undo:[3] Redo:[0]
矩形容器 :[0]
圆形容器 :[0]
圆角矩形容器:[0]
==========删除复合对象==========
----------撤销一步----------
Undo:[2] Redo:[1]
矩形容器 :[1] (0x1,(1,1,200,100))
圆形容器 :[4] (0x1,(1,1,5)) (0x2,(201,1,5)) (0x3,(201,101,5)) (0x4,(1,101,5))
圆角矩形容器:[1] (0x1,R:[0x1] C:[0x1] C:[0x2] C:[0x3] C:[0x4] )
==========撤销一步==========
----------重做一步----------
Undo:[3] Redo:[0]
矩形容器 :[0]
圆形容器 :[0]
圆角矩形容器:[0]
==========重做一步==========
*******************************************************************************/

#if 0

从上面的代码我们可以看出,已经成功的实现了复合类的派生类。这一点非常便于我
们给复合类添加额外的操作。我们还可以看出,上面的可派生的复合类的创建、修改和删
除过程和前面的复合类完全相同。为了以后使用的方便,这个可派生复合类模板compound
将会替换前一篇文章中的compound保存到文件“compound.h”中。

本章完。

从上面的compound类的实现可以看出,对于派生自compound的复合类,还不能够处理
复合类里面包含其它复合类的情况,至于如何解决,请关注本系列后续的文章。

敬请关注!


上一篇:撤销和重做(Undo和Redo)的C++完美实现(7-1)
  下一篇:撤销和重做(Undo和Redo)的C++完美实现(8)
我的博客
http://blog.csdn.net/pandaxcl/
#endif

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值