C++ primer 第15章 简单文本查找器例子代码

来源:互联网 发布:朋友圈链接制作软件 编辑:程序博客网 时间:2024/06/08 14:14

主要分析一下代理模式。

C++ primer中这段代码的设计一定是有问题的,有待优化。因为竟然把代理器和派生类放在同一个源码文件中,这一定是设计缺陷。但是目前我没有能力去更正这种设计缺陷,或者说我没时间多余,我要重新开始找工作啦。写这篇博客的目的在于练手结束之后发现我可以分辨出设计模式、智能指针、C++句柄类的用法啦。

class Query_base{private:friend class Query;protected:virtual ~Query_base(void){};typedef TextQuery::line_no line_no;private:virtual std::set<line_no> eval(const TextQuery &) const = 0;virtual std::ostream & display(std::ostream & out = std::cout) const = 0;};

虚基类对象的代码,宣布代理类Query为友元类,同时采用priavte的形式对外提供接口。也就是说,对外界非友元类来说是不可访问,友元类只能在接口形式访问派生类形成动态绑定,某种意义上来说,就你继承了你老爸的王位。老管家作为国王秘书长开始对你服务,或者说你有个叔叔是摄政王。这两位老人是你老爸的挚友,帮你管理国家,即便你很不乐意或者说年少不经事能信任的只有这几位老臣子。这在某种意义上来说和封装想反。

class BinaryQuery :public Query_base{protected:BinaryQuery(const Query &left,const Query & right,std::string op):lhs(left),rhs(right),oper(op){};virtual~BinaryQuery(void){};std::ostream & display(std::ostream & os) const{return os<<"("<< lhs <<" "<< oper<<" "<<rhs<<")";}const Query lhs,rhs;const std::string oper;};class OrQuery :public BinaryQuery{friend Query operator |(const Query & first,const Query & second);OrQuery(Query left,Query right):BinaryQuery(left,right,"|"){};std::set<line_no> eval(const TextQuery & file)const{std::set<line_no> right = rhs.eval(file);std::set<line_no> ret_Lines = lhs.eval(file);ret_Lines.insert(right.begin(),right.end());return ret_Lines;}};#include <algorithm>class AndQuery :public BinaryQuery{friend Query operator &(const Query & first,const Query & second);AndQuery(Query left,Query right):BinaryQuery(left,right,"&"){};std::set<line_no> eval(const TextQuery & file )const{std::set<line_no> left = lhs.eval(file),right = rhs.eval(file);std::set<line_no> ret_Lines;std::set_intersection(left.begin(),left.end(),right.begin(),right.end(),std::inserter(ret_Lines,ret_Lines.begin()));return ret_Lines;}};class NotQuery :public Query_base{friend Query operator ~(const Query &);NotQuery(const Query q):query(q){};std::set<line_no> eval(const TextQuery & file)const{std::set<line_no> hasVal = query.eval(file);std::set<line_no>ret_lines;for (line_no n = 0; n != file.size(); ++n){if (hasVal.find(n)==hasVal.end()){ret_lines.insert(n);}}return ret_lines;}std::ostream & display(std::ostream & os) const{return os<< "~("<<query<<")";}const Query query;};class WordQuery :public Query_base{friend class Query;WordQuery(const std::string &s):query_word(s){};std::set<line_no> eval(const TextQuery & t)const{return t.RunQuery(query_word);}std::ostream & display(std::ostream & os) const{return os<<query_word;}std::string query_word;};

以上为三个派生类,均以不同形式开放访问,比如WordQuery对代理全开放,而其他的派生类则开放给对应访问函数。通俗点理解:祭天是每个国王应尽的义务。继承至父类的private接口全是义务,有个友元类会不断的给你任务或者日程安排。不喜欢去祭天,可是摄政王他大爷叫你去,你不得不去。

皇帝管理国家要么通过摄政王,要么通过丞相,本例中的摄政王就是Query,代码如下:

class Query{private:friend Query operator ~(const Query &);friend Query operator |(const Query & first,const Query & second);friend Query operator &(const Query & first,const Query & second);friend std::ostream & operator<<(std::ostream &os,const Query & query);public:Query(const std::string & );//复制构造函数Query(const Query &c):m_pQureyBase(c.m_pQureyBase),m_pUse(c.m_pUse){++*m_pUse;};~Query(void);Query & operator = (const Query & other);//代理模式std::set<TextQuery::line_no> eval(const TextQuery & t) const{ return m_pQureyBase->eval(t);};std::ostream & display(std::ostream & os) const {return m_pQureyBase->display(os); };private:Query(Query_base *queryBase):m_pQureyBase(queryBase),m_pUse(new std::size_t(1)){};void DecrUse(){if (--*m_pUse==0){delete m_pQureyBase;delete m_pUse;}}private:Query_base * m_pQureyBase;std::size_t * m_pUse;};
外界通过eval和display来和Query_Base一族交互。俨然Query这个代理才是王位的所有者。这个就是代理模式的思想,将具体的实现封装,通过代理的形式提供访问。同时,我们再一次看到智能指针。

void DecrUse()
{
if (--*m_pUse==0)
{
delete m_pQureyBase;
delete m_pUse;
}
}


//复制构造函数
Query(const Query &c):m_pQureyBase(c.m_pQureyBase),m_pUse(c.m_pUse){++*m_pUse;};

//赋值操作符重载

inline Query & Query::operator = (const Query & other)
{
++*other.m_pUse;
DecrUse();
m_pQureyBase = other.m_pQureyBase;
m_pUse = other.m_pUse;
return *this;
}

没有和cocos2dx那样提供对外的访问,在内部管理内存,这点更加安全,不存在用户使用不恰当的隐患。

我的地图解析器也套用了这个机制,为2D/3D的A*算法解决实际的节点问题。就只剩下启发函数啦。

附代码链接:

代码例子,点击下载

0 0