C++PRIMER-5TH 15.9 文本查询程序再探 练习理解(二)

从对象角度进行的思考。2014-01-21

#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <memory>
#include <algorithm>
using namespace std;
class QueryResult
{
public:
	friend ostream &print(ostream &, const QueryResult &);

	QueryResult(string s, shared_ptr<set<int>> w, shared_ptr<vector<string>> f) :word(s), wordlineSet(w), file(f)
	{
		//cout<< "QueryResult construst"<<endl;
		//cout << *file->begin()<<endl;
	}
	set<int>::iterator begin() { return wordlineSet->begin(); }
	set<int>::iterator end() { return wordlineSet->end(); }
	std::shared_ptr<std::vector<std::string>> get_file() { return file; }

private:
	string word;
	shared_ptr<set<int>> wordlineSet;
	shared_ptr<vector<string>> file;

};

class TextQuery
{
public:
	TextQuery(ifstream &is) : file(new vector<string>)
	{
		string text;
		while (getline(is, text))
		{
			//cout << "TextQuery construct"<<endl;
			file->push_back(text);
			//cout << text <<endl;
			//cout << file->size()<<endl;
			int lineNumber = file->size() - 1;//存入vector的行数应该是实际行数减1
			istringstream line(text);
			string word;
			while (line >> word)
			{
				auto &lines = wordmap[word];
				if (!lines)
					lines.reset(new set<int>);
				lines->insert(lineNumber);
				/*
				关于. 和 -> 操作:
				.是对lines本身操作
				->是对lines(智能指针)所指向的对象操作
				*/
			}
		}
	}
	QueryResult query(const string &s) const
	{
		static shared_ptr<set<int>> nodata(new set<int>);
		auto wordloc = wordmap.find(s);
		if (wordloc == wordmap.end())
			return QueryResult(s, nodata, file);
		else
			return QueryResult(s, wordloc->second, file);
	}
private:
	shared_ptr<vector<string>> file;
	map<string, shared_ptr<set<int>>> wordmap;
};

class Query_base
{
	friend class Query;
protected:
	virtual ~Query_base() = default;
private:
	virtual QueryResult eval(const TextQuery&) const = 0
	{
		cout << "Query_base::eval()" << endl;
	}
	virtual string rep() const = 0;
};

class Query
{
	friend Query operator~(const Query &);
	friend Query operator|(const Query &, const Query &);
	friend Query operator&(const Query &, const Query &);
public:
	Query(const string&);//构造函数
	QueryResult eval(const TextQuery &t) const
	{
		return q->eval(t);
	}
	string rep() const
	{
		return q->rep();
	}
private:
	Query(shared_ptr<Query_base> query) : q(query) 
	{
		cout << "Query(shared_ptr<Query_base> query) " << endl;
	}

	shared_ptr<Query_base> q;
};

//重载输出(<<)操作符
std::ostream & operator<<(std::ostream &os, const Query &query)
{
	return os << query.rep();
}


//单词查询类  
class WordQuery : public Query_base {
	friend class Query;
	WordQuery(const string &s) : query_word(s) {}
	QueryResult eval(const TextQuery &t) const 
	{ 
		cout << "WordQuery  eval()  "<< endl;
		return t.query(query_word);
	}
	string rep() const 
	{ 
		cout <<"***WordQuery  rep()"<< endl;
		return query_word; 
	};
	string query_word;
};
//Query接口实现动态绑定WordQuery 
inline Query::Query(const std::string &s) : q(new WordQuery(s)) 
{
	cout << "Query::Query(const std::string &s) " <<s<< endl;
}

//取反查询  
class NotQuery : public Query_base {
	friend Query operator~ (const Query &); //友元是取反函数  
	NotQuery(const Query &q) : query(q) 
	{
		cout << "NotQuery construct" << endl;
	}
	string rep() const { return "~(" + query.rep() + ")"; }
	QueryResult eval(const TextQuery &t) const;
	Query query;
};
//实现取反操作, 动态绑定NotQuery对象  
//最终使用的是WordQuery类, Query构建需要WordQuery, 再传入NotQuery;  
inline Query operator~ (const Query &operand)
{
	cout << "Query operator~ " << endl;
	return shared_ptr<Query_base>(new NotQuery(operand));
}

//二元查询, 没有eval, 则继承纯虚函数
class BinaryQuery : public Query_base {
protected:
	BinaryQuery(const Query &l, const Query &r, std::string s) :
		lhs(l), rhs(r), opSym(s) 
	{
		cout <<"BinaryQuery" << endl;
	}
	std::string rep() const {
		return "(" + lhs.rep() + " " + opSym + " " + rhs.rep() + ")";
	}
	Query lhs, rhs;
	std::string opSym;
};

//取并查询
class AndQuery : public BinaryQuery {
	friend Query operator& (const Query&, const Query&);
	AndQuery(const Query& left, const Query& right) : BinaryQuery(left, right, "&") 
	{
		cout << "AndQuery" << endl;
	}
	QueryResult eval(const TextQuery&) const;
};

inline Query operator& (const Query& lhs, const Query& rhs) 
{
	cout << "Query operator& " << endl;
	return shared_ptr<Query_base>(new AndQuery(lhs, rhs));
}

//取或查询
class OrQuery : public BinaryQuery {
	friend Query operator| (const Query&, const Query&);
	OrQuery(const Query& left, const Query& right) : BinaryQuery(left, right, "|") 
	{
		cout <<"OrQuery" << endl;
	}
	QueryResult eval(const TextQuery&) const;
};

inline Query operator| (const Query& lhs, const Query& rhs) 
{
	cout << "Query operator| " << endl;
	return shared_ptr<Query_base>(new OrQuery(lhs, rhs));
}

QueryResult OrQuery::eval(const TextQuery& text) const
{
	auto right = rhs.eval(text), left = lhs.eval(text);
	auto ret_lines = std::make_shared<std::set<int> >(left.begin(), left.end());
	ret_lines->insert(right.begin(), right.end());
	return QueryResult(rep(), ret_lines, left.get_file());
}

QueryResult AndQuery::eval(const TextQuery& text) const {
	auto left = lhs.eval(text), right = rhs.eval(text); //调用的是WordQuery的eval
	auto ret_lines = std::make_shared<std::set<int>>();
	set_intersection(left.begin(), left.end(), right.begin(), right.end(),
		inserter(*ret_lines, ret_lines->begin()));
	return QueryResult(rep(), ret_lines, left.get_file());
}

QueryResult NotQuery::eval(const TextQuery& text) const
{
	cout << " QueryResult NotQuery::eval(const TextQuery& text) const"<< endl;
	auto result = query.eval(text); //调用WordQuery.eval;
	auto ret_lines = std::make_shared<std::set<int>>();
	auto beg = result.begin(), end = result.end();
	auto sz = result.get_file()->size();
	for (size_t n = 0; n != sz; ++n) {
		if (beg == end || *beg != n)
		{
			cout << n << endl;
			//cout << *beg << endl;
			ret_lines->insert(n);
		}
		else if (beg != end)
			++beg;
	}
	return QueryResult(rep(), ret_lines, result.get_file());
}

bool get_word(std::string& str) {
	std::cout << "enter word to look for, or q to quit: " << std::endl;
	if (!(std::cin >> str) || str == "q"){
		std::cout << str;
		return false;
	}
	else{
		std::cout << str;
		return true;
	}
}

string make_plural(const int length, const string s1, const string s2)
{
	if (length == 0)
		return s1;
	if (length == 1)
		return s1;
	else
		return s2;
}

ostream &print(ostream & os, const QueryResult &qr)
{
	//cout << *(qr.file->begin())<<endl;
	//cout<< "print function running"<<endl;
	os << qr.word << " occurs " << qr.wordlineSet->size() << " " << make_plural(qr.wordlineSet->size(), "time", "times") << endl;
	for (auto num : *qr.wordlineSet)
		os << "  (line " << num + 1 << ")" << *(qr.file->begin() + num) << endl;
	return os;
}

void runQueries(ifstream &infile)
{
	TextQuery t1(infile);
	while (true)
	{
		cout << "Enter word to look for,or q to quit" << endl;
		string s;
		if (!(cin >> s) || s == "q")
			break;
		print(cout, t1.query(s)) << endl;
	}
}

void main()
{
	ifstream in;
	//runQueries(in);
	in.open("d://article.txt");
	TextQuery file = in;

	Query q1("the");
	Query q(q1);
	//Query q = Query("the");
	//Query q = ~Query("was");
	//Query q = Query("were") | Query("was");
	//Query q = Query("was") & Query("the");
	//Query q = Query("was") & Query("the") | Query("were");
	cout << "-=--=--=-=-=-=-=---==-=-==-=-=-=-=" << endl;
	const auto results = q.eval(file);
	cout << "Executing Query for: " << q << endl;
	print(cout, results) << endl;

}

------------------------------------------------------------

从main()函数说起

void main()
{
	ifstream in;
	//runQueries(in);
	in.open("d://article.txt");
	TextQuery file = in;

	Query q1("the");
	Query q(q1);
	//Query q = Query("the");
	//Query q = ~Query("was");
	//Query q = Query("were") | Query("was");
	//Query q = Query("was") & Query("the");
	//Query q = Query("was") & Query("the") | Query("were");
	cout << "-=--=--=-=-=-=-=---==-=-==-=-=-=-=" << endl;
	const auto results = q.eval(file);
	cout << "Executing Query for: " << q << endl;
	print(cout, results) << endl;

}

Query q1("the");

Query q(q1);

这两句,分别展示了Query类的两种构造函数。

第一种是,接受一个字符串,给类成员对象 q 赋值为 new WordQuery(s) ,q 的类型是shared_ptr<Query_base>,也就是说,q 的值是地址。 

Query(const std::string &s) : q(new WordQuery(s))
{
  cout << "Query::Query(const std::string &s) " <<s<< endl;
}

第二种是,接受一个shared_ptr<Query_base>的变量(其实是个地址),然后把该地址赋给成员变量 q,main()函数中,Query q(q1) ,q1的成员变量是 new WordQuery(s)的地址。

Query(shared_ptr<Query_base> query) : q(query)
{
  cout << "Query(shared_ptr<Query_base> query) " << endl;
}

总结起来,赋值到底赋的是什么?是类型中的成员变量!! (暂不涉及类型转换)

下面看最复杂的。

Query q = Query("was") & Query("the") | Query("were");

执行顺序先确定下,((was & the) | were)。

首先,等号右边,有三个带字符的Query类型,所以,有调用三次Query(const std::string &s) ,各自对象内的成员变量q都有各自的地址。

接下来,执行内层括号的 & 运算符,形参列表是,分别在&号左右两侧对象的引用,实际上传的是两个地址,因为Query类型的对象只有一个成员变量,并且是地址值。

Query operator& (const Query& lhs, const Query& rhs)
{
  cout << "Query operator& " << endl;
  return shared_ptr<Query_base>(new AndQuery(lhs, rhs));
}

因此(was & the) 就等于 shared_ptr<Query_base>(new AndQuery(lhs, rhs)),说白了就是个地址。我暂时把这个地址 定义为 addr。(这么定义,其实是因为编译器确实创建了一个Query temp = (was & the)的地址,只是这是一个临时变量)

接着addr | Query("were"),| 运算符,形参列表同样接受两个对象(其实是地址)。

Query operator| (const Query& lhs, const Query& rhs)
{
  cout << "Query operator| " << endl;
  return shared_ptr<Query_base>(new OrQuery(lhs, rhs));
}

最后返回的是 shared_ptr<Query_base>(new OrQuery(lhs, rhs)),一个地址。C++很有意思的地方就在这里,地址指向对象,对象里存的还是地址。。

程序运行结果:

Query::Query(const std::string &s) were
Query::Query(const std::string &s) the
Query::Query(const std::string &s) was
Query operator&
BinaryQuery
AndQuery
Query(shared_ptr<Query_base> query)
Query operator|
BinaryQuery
OrQuery
Query(shared_ptr<Query_base> query)

从运行结果中,可以看出来,每一个类的构造函数运行的情况。

上面执行的只是 Query q = Query("was") & Query("the") | Query("were"); 这么一句。

 

 

posted on 2014-01-21 23:19  WK23  阅读(720)  评论(0)    收藏  举报

导航