解释器模式

非常像自己做过的 c++ primer 里 query 作业.

重点是将需要解释的语言,组织成抽象的语法树,用类去构建语法树.

参考理解的文章, 但实现上有不同

自己实现的代码地址

TextQuery

最开始仅是查询某个单词所在的行数。 文本存储到内存,选择 vector<string> map 数据结构保存查询结果 map<string, set<int>>, string 为查询单词,set 保存行数 QueryResult result 保存查询结果。 query 函数, QueryResult query(const string & query_word); 依据 word 返回对应的行号 set<int>,QueryResult 封装该 set; 有 1 个 display 函数, 其他。

OOP 实现

真正的面向对象,类关系:

Query_base

WordQuery NotQuery BinaryQuery

AndQuery OrQuery

WordQuery 解决单个查询

Query

Query 隐藏继承细节,核心成员是一个指向基类的 base 指针. 核心思想就是封装基类指针!,然后灵活的调用下面的函数. QueryResult eval(TextQuery & t);

问题最后抽象成为一个布尔查询表达式:

Query q = ~(Query("good") | (Query("boy") & Query("girl")));
QueryResult r= q.eval(TextQuery("xxx.file");

这里调用了很多次构造函数:

1 重载~运算符, 构造了1个Query, query_base 指向OrQuery;
2 OrQuery也是构造出来的,它的参数根据表达式推断,是个 x|x 返回的Query;
	构造后,OrQuery的pquery指向x|x;
3 x|x又是重载了|,又构造Query, 同时new了1个OrQuery;
4 OrQuery构造时的参数有2个,分别用2个指针指向:
	lquery = &Query("good") ;
		Qeury("word")是默认的Query构造,接受string, 5;
	rquery = &( x&x )
5 构造Query("word),返回Query
6 x&x 重载&, 返回新Query, 同时构造新的AndQuery
7 AndQuery 构造接收2个Qquery,也有2个指针指向他们
	lquery指向Query("boy);
	rquery指向Query("girl);
8 构造Query("boy"),返回Query
9 构造Query("girl"),返回Query

一共调用了 9 次…

本质上就是虚函数里再调用虚函数,形成层次, 最外层的优先级最低(~),括号扩起来的优先级别最高(&).

q.eval –>NotQuery::eval NotQuery 里的基类指针,指向了一个 OrQuery

OrQuery::eval, 含有两个指针,一个指向 WordQuery,一个指向 AndQuery, 因此分别调用了 WordQuery::eval 和 AndQuery::eval

WordQuery::eval 检查单词“good” AndQuery::eval 又含 2 个指针(Query 对象),指向 2 个 WordQuery

WordQuery::eval 检查单词“boy” WordQuery::eval 检查单词“girl” 继续做 AndQuery::eval 的 And 动作 继续做 OrQuery::eval 的 Or 动作

继续做 NotQuery::eval 未完成的 Not 动作

例如 Query Query: 操作返回一个 Query, 用派生类的指针构造。
friendly Query operator|(const Query a, const Query b)
{
	return new OrQuery(a,b);
}
//这里是隐式转换,调用下面的转换构造函数
Query(Query * ptr) : base(ptr) {}

OrQuery 派生自 BinaryQuery,因此派生类的构造又是调用了基类的构造函数

OrQuery(Query a, Query b) : BinaryQuery(a,b,"|") {}

Binary 将 a,b,保存到自己的成员变量 Query left 和 Query right 中。

智能指针的引入

在创建表达式的 query 时,相当于 Query* base = new OrQuery(…);需要手动释放,用智能指针解决手动释放的问题。 另外定义一个类为 share_ptr 和直接定义一个对象 使用上其实并没有区别,

shared_ptr<Class> ptrc;
Class * c;
Class c;

区别在: 1 内存维护上,ptrc 可以自动管理内存释放,指针分配的内存需要 delete,普通对象跟随生命周期自动析构 2 资源上,对象赋值时发生拷贝,shared_ptr 和指针共享; 3 生命周期 share_ptr 取决引用值,指针 delete,而且必须在定义他的类对象结束之前, 普通对象跟随定义他的类的生命周期