首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > C++ >

C++primer再谈文本查询中的构造函数调用有关问题

2013-08-01 
C++primer再谈文本查询中的构造函数调用问题,求助Query.h//Query.h//Query类及Query_base类层次的头文件#i

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

这是输出结果:
C++primer再谈文本查询中的构造函数调用有关问题

我想知道为什么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是一份新的拷贝,所以会调用拷贝构造函数

热点排行