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"); 这么一句。
浙公网安备 33010602011771号