C++面向对象编程——条件查询程序

没搞明白。

题目来源:C++ Primer 15.41题目。

查询满足诸如  ~a&b|c条件的文本。

Query.h

#ifndef QUERY_H
#define QUERY_H

#include "TextQuery.h"
#include <string>
#include <set>
#include <iostream>
#include <fstream>

using namespace std;


///用作具体查询类型的基类抽象类
class Query_base{
	friend class Query;

	protected:
	typedef TextQuery::line_no line_no;
	virtual ~Query_base(){}

	private:
	//
	virtual set<line_no>
		eval(const TextQuery &)const =0;
	virtual ostream&
		display(ostream& =cout) const =0;
};


///Query句柄类
class Query {
	//这些操作符需要访问 Query_base*的构造函数
	friend Query operator ~(const Query &);
	friend Query operator |(const Query &,const Query &);
	friend Query operator &(const Query &,const Query &);
	public:
	Query(const string&);//建立新的WordQuery对象
	
	//管理指针及使用计数的复制控制成员
	Query(const Query & c):q(c.q),use(c.use){++*use;}
	~Query(){decr_use();}
	Query& operator=(const Query &);

	//接口函数:将调用相应的Query_base 操作
	set<TextQuery::line_no>
		eval(const TextQuery &t)const{
			return q->eval(t);
		}
	ostream &
		display(ostream &os)const {
			return q->display(os);
		}
	
	private:
	Query(Query_base* query):q(query),use(new size_t(1)){}
	Query_base *q;
	size_t *use;
	void decr_use(){
		if(--*use==0){
			delete q;
			delete use;
		}
	}
};

inline Query & Query::operator=(const Query &rhs){
	++*rhs.use;
	decr_use();
	q=rhs.q;
	use=rhs.use;
	return *this;
}

// I/O操作符一般定义为非成员,
//因为类成员的左操作数必为类对象,item<<cout与日常习惯相反
inline ostream& operator<<(ostream &os,const Query &q){
	return q.display(os);
}

//WordQuery
class WordQuery: public Query_base{
	friend class Query;//Query使用WordQuery的构造函数
	WordQuery(const string &s):query_word(s){}
	
	//具体类WordQuery定义所有继承来的纯虚函数
	set<line_no> eval(const TextQuery &t)const{
		return t.run_query(query_word);	
	}

	ostream& display(ostream& os)const {
		return os<<query_word;
	}
	
	string query_word;
};

//这个函数需要用到WordQuery的构造函数
inline Query::Query(const string &s):q(new WordQuery(s)),use(new size_t(1) ){}


//NotQuery类
class NotQuery :public Query_base{
	friend Query operator ~(const Query &);
	NotQuery(Query q):query(q){}

	//具体类NotQuery定义所有继承而来的纯虚函数
	set<line_no>
		eval(const TextQuery &t) const;
	ostream& display(ostream& os)const{
		return os<<"~("<<query<<")"<<endl;
	}
	const Query query;
};

//二元抽象类
class BinaryQuery:public Query_base{
	protected:
	BinaryQuery(Query left,Query right,string op):
		lhs(left),rhs(right),oper(op){}
	
	//抽象类BinaryQuery不定义eval(此时仍为抽象类)
	ostream& display(ostream &os)const{
		return os<<"("<<lhs<<")"<<oper<<"("<<rhs<<")";
	}
	const Query lhs,rhs;
	const string oper;
};

class AndQuery: public BinaryQuery{
	friend Query operator&(const Query&,const Query&);
	
	AndQuery(Query left,Query right):
		BinaryQuery(left,right,"&"){}

	//具体类AndQuery继承display并保持为虚函数
	set<line_no> eval(const TextQuery&)const;
};

class OrQuery:public BinaryQuery{
	friend Query operator|(const Query&, const Query&);
	OrQuery(Query left,Query right):BinaryQuery(left,right,"|"){};

	//具体类OrQuery继承display并保持为虚函数
	set<line_no> eval(const TextQuery&)const;
};

///
inline Query operator &(const Query &lhs,const Query &rhs){
	return new AndQuery(lhs,rhs);
}

inline Query operator |(const Query &lhs,const Query &rhs){
	return new OrQuery(lhs,rhs);
}

inline Query operator ~(const Query &rhs){
	return new NotQuery(rhs);
}

#endif

Query.cpp

#include "Query.h"
#include "TextQuery.h"
#include <set>
#include <algorithm>
#include <iostream>

using namespace std;

//返回不在其操作结果中的行号集合
set<TextQuery::line_no>
NotQuery::eval(const TextQuery &file) const{
	//计算其操作数的结果集
	set<TextQuery::line_no> has_val=query.eval(file);

	set<line_no> ret_lines;

	for(TextQuery::line_no n=0;n!=file.size();n++){
		if(has_val.find(n)==has_val.end())
			ret_lines.insert(n);
	}
}

//返回其操作数结果集的交集
set<TextQuery::line_no>
AndQuery::eval(const TextQuery &file)const{
	set<TextQuery::line_no> left=lhs.eval(file),right=rhs.eval(file);
	set<line_no> ret_lines;//保存运算结果
	
	//将左右操作数结果的交接写至ret_lines
	set_intersection(left.begin(),left.end(),right.begin(),right.end(),
		inserter(ret_lines,ret_lines.begin()));
	return ret_lines;
}

//返回操作数结果集的并集
set<TextQuery::line_no>
OrQuery::eval(const TextQuery &file)const{
	set<line_no> right=rhs.eval(file),
		 ret_lines=rhs.eval(file);
	/*
	将未在ret_lines中出现的right中的行号插入到ret_lines中,
	retu_lines.inset(right.begin(),right.end());所用的编译器不支持
	带两个迭代器参数的insert函数,改用如下代码:
	*/
	for(set<line_no>::const_iterator iter=right.begin();
		iter!=right.end();++iter){
		ret_lines.insert(*iter);
	}
	return ret_lines;
}





TextQuery.h

/*使用set容器存储行号*/
#ifndef	TEXTQUERY_H
#define TEXTQUERY_H

#include <string>
#include <vector>
#include <set>
#include <map>
#include<cctype>
#include<iostream>
#include <fstream>
#include<cstring>
using namespace std;

class TextQuery{
public:
	//类型别名
	typedef string::size_type str_size;
	typedef vector<string>::size_type line_no;
	
	//接口
	//read_file 建立给定文件的内部数据结构
	void read_file(ifstream &is){
		store_file(is);
		build_map();
	}

	//run_query查询给定单词并返回该单词所在的行的行号集合
	set<line_no> run_query(const string&) const;
	
	//text_line返回输入文件中指定行号对应的行
	string text_line(line_no) const;

	line_no size() const;

private:
	//read_file所用的辅助函数
	void store_file(ifstream &);//存储输入文件
	void build_map();//将每一个单词与一个行号集合相关联

	//保存输入文件
	vector<string> lines_of_text;

	//将单词与出现该单词的行的行号集合相关联
	map<string,set<line_no> > word_map;

	//去掉标点并将字母变成小写
	static string cleanup_str(const string&);	
};
#endif


TextQuery.cpp

#include "TextQuery.h"
#include <sstream>

string TextQuery::text_line(line_no line)const{
	if(line<lines_of_text.size())
		return lines_of_text[line];
	//throw out_of_range("line number out of range");
}

//读输入文件,将每行存储为lines_of_text的一个元素
void TextQuery::store_file(ifstream &is){
	string textline;
	while(getline(is,textline))
		lines_of_text.push_back(textline);
}

//在输入vector中找以空白为间隔的单词
void TextQuery::build_map(){
	//处理输入vector中的每一行
	for(line_no line_num=0;line_num!=lines_of_text.size();++line_num){
		//一次读一个单词
		istringstream line(lines_of_text[line_num]);
		string word;
		while(line>>word){
			//将行号加入到set容器中
			//若单词不在map容器中,下标操作将加入该单词
			word_map[cleanup_str(word)].insert(line_num);
		}
	}
}

set<TextQuery::line_no>
TextQuery::run_query(const string& query_word)const{
	//注意,为了避免在word_map中加入单词,使用find函数而不用下标操作
	map<string,set<line_no> >::const_iterator
		loc=word_map.find(query_word);
	if(loc==word_map.end())
		return set<line_no>();
	else
		//获取并返回与该单词关联的行号set对象
		return loc->second;
}

//去掉标点并将字母变成小写
string TextQuery::cleanup_str(const string &word){
	string ret;
	for(string::const_iterator it=word.begin();
		it!=word.end();++it){
		if(!ispunct(*it))
			ret+=tolower(*it);
	}
	return ret;
}

//获取文本行数
vector<string>::size_type TextQuery::size() const{
	return lines_of_text.size();
}

main.cpp

/*
	使用TextQuery类、Query类及Query_base类层次,
	计算和打印如图15-4所示的查询
	Query("fiery")&Query("bird")|Query("wind")
*/

#include "Query.h"
#include "TextQuery.h"

string 
make_plural(size_t ctr,const string& word,const string& ending){
	return (ctr==1)?word:word+ending;
}

ifstream& 
open_file(ifstream& in,const string& file){
	in.close();//close in case it was already open
	in.clear();//clear any existing errors
	//if the open fials, the stream will be in an invalid state
	in.open(file.c_str());//open the file we were given
	return in;//condition state is good if open succeeded
}

void print_results(const set<TextQuery::line_no>& locs,const TextQuery& file){

	typedef set<TextQuery::line_no> line_nums;
	line_nums::size_type size=locs.size();

	//如果找到匹配的结果,则输出匹配的行数
	cout<<"match occurs "<<size<<" "<<make_plural(size,"time","s")<<endl;

	//输出出现该单词的每一行
	line_nums::const_iterator it=locs.begin();
	for(; it!=locs.end();++it){
		cout<<"\t(line"
		//行号从1开始
		<<(*it)+1<<")"
		<<file.text_line(*it)<<endl;
	}
}

int main(int argc,char **argv){
	//打开要在其中进行查询的文本文件
	ifstream infile;
	if(!open_file(infile,"a.txt")){
		cerr<<"No input file!"<<endl;
		return 1;
	}
	TextQuery file;
	file.read_file(infile);//读入文本,建立map容器

	typedef set<TextQuery::line_no> line_nums;
	//构造查询
	Query q=Query("the")&Query("such")|Query("will");

	//计算查询,获得匹配行的行号集合
	const line_nums& locs=q.eval(file);

	//输出查询表达式
	cout<<"\nExecuted Query for: "<<q<<endl;

	//输出查询结果
	print_results(locs,file);

	return 0;
}

objects= main.o Query.o TextQuery.o

test:$(objects)
	g++ -o test $(objects)
main.o:
Query.o:TextQuery.h
TextQuery.o:


.PHONY :clean
clean:
	rm test $(objects)



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值