C++primer再谈文本查询中的构造函数调用问题,求助
Query.h
//Query.h
//Query类及Query_base类层次的头文件
#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_base继承层次的句柄类
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){static int i=0;++*use;cout<<"Query(const Query &c)调用了"<<++i<<"次"<<endl;}
~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;
}
inline ostream&
operator<<(ostream &os,const Query &q)
{
return q.display(os);
}
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; //要查找的单词
};
inline Query::Query(const string &s):q(new WordQuery(s)),use(new size_t(1)){static int i=0;cout<<"第"<<++i<<"次调用Query(const string &s)"<<endl;}
class NotQuery:public Query_base
{
friend Query operator~(const Query &);
NotQuery(Query q):query(q){}
//具体类NotQuery定义所有继承而来的纯虚函数
set<line_no> eval(const TextQuery&) const;
ostream& display(ostream &os) const
{return os<<"~("<<query<<")";}
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,"&"){cout<<"正在调用AndQuery构造函数"<<endl;}
//具体类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,"|"){cout<<"正在调用OrQuery构造函数"<<endl;}
//具本类AndQuery继承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 &oper)
{
return new NotQuery(oper);
}
#endif
TextQuery.h
//TextQuery.h
//TextQuery类的头文件
//使用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_H
main.cpp
//main.cpp
//使用TextQuery类,Query类及Query_base类层次
//Query("fiery") & Query("bird") | Query("wind")
#include "Query.h"
#include "TextQuery.h"
string make_plural(size_t a,const string& b,const string& c)
{
return a>1?b+c:b;
}
ifstream& open_file(ifstream& infile,const string& file)
{
infile.close();
infile.clear();
infile.open(file.c_str());
return infile;
}
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;
string filename;
cout<<"please input file name:"<<endl;
cin>>filename;
infile.open(filename);
if(!open_file(infile,"data.txt"))
{
cerr<<"No input file!"<<endl;
return EXIT_FAILURE;
}
TextQuery file;
file.read_file(infile); //读入文本,建立map容器
typedef set<TextQuery::line_no> line_nums;
//构造查询
Query q=Query("fiery")&Query("bird")|Query("wind");
//计算查询,获得匹配行的行号集合
const line_nums &locs=q.eval(file);
//输出查询表达式
cout<<"\nExecuted Query for:"<<q<<endl;
//输出查询结果
print_results(locs,file);
system("pause");
return 0;
}
Query.cpp
//Query.cpp
//Query类及Query_base类层次的实现文件
#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;
//检查输入文件中的每一行,看该行的行号是否在has_valK
//如果不在,将该行的行号加入到ret_lines
for(TextQuery::line_no n=0;n!=file.size();++n)
if(has_val.find(n)==has_val.end())
ret_lines.insert(n);
return ret_lines;
}
//返回其操作数结果集的交集
set<TextQuery::line_no>
AndQuery::eval(const TextQuery& file) const
{
//计算其左右操作数的结果集
set<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=lhs.eval(file);
//将未在ret_lines中出现的right中的行号插入到ret_lines中
//ret_lines,insert(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.cpp
//TextQuery.cpp
//TextQuery类的实现文件
//使用set容器存储行号
#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中找以空白为间隔的单词
//将单词以及出现该单词的行的行号一起放入word_map
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>(); //找不到,返回空的set对象
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();
}
data.txt文本中的内容:
fiery and bird
or wind
这是输出结果:

我想知道为什么Query(const Query &c) 会调用6次?在调用重载& 和|的时候。 看了好久了。一直没看明白。 C++ 类
[解决办法]
因为
AndQuery(Query left,Query right):
BinaryQuery(Query left,Query right,string op):
都接受值类型,导致了额外的复制。
换成这样就好了
AndQuery(Query const& left,Query const& right):
BinaryQuery(Query const& left,Query const& right,string op):
[解决办法]
AndQuery(Query left,Query right):
BinaryQuery(Query left,Query right,string op):
这个是传值,再调用这种函数的时候,会创建一份零时变量,你这里left,right是一份新的拷贝,所以会调用拷贝构造函数