《C++ Primer》第19章 特殊工具与技术
19.5节 嵌套类 习题答案
练习19.20:将你的QueryResult类嵌套在TextQuery中,然后重新运行12.3.2节(第435页)中使用了TextQuery的程序。
【出题思路】嵌套类的定义与使用练习。
【解答】
class TextQuery
{
public:
class QueryResult;
//其他成员的定义
};
class TextQuery::QueryResult
{
friend std::ostream& print(std::ostream&, const QueryResult&);
public:
typedef std::vector<std::string>::size_type line_no;
typedef std::set<line_no>::const_iterator line_it;
QueryResult(std::string s, std::shared_ptr<std::set<line_no>> p, std::shared_ptr<std::vector<std::string>> f);
//其他成员的定义
};
TextQuery::QueryResult::QueryResult(std::string s, std::shared_ptr<std::set<line_no>> p, std::shared_ptr<std::vector<std::string>> f)
:sought(s), lines(p), file(f)
{
}
完整的示例:
#include <cstddef>
using std::size_t;
#include <string>
using std::string;
#include <iostream>
using std::cout;
using std::endl;
#ifndef MAKE_PLURAL_H
#define MAKE_PLURAL_H
// return the plural version of word if ctr is greater than 1
inline
string make_plural(size_t ctr, const string &word,
const string &ending)
{
return (ctr > 1) ? word + ending : word;
}
#endif // MAKE_PLURAL_H
#ifndef PROGRAM19_20_H
#define PROGRAM19_20_H
#include <memory>
#include <string>
#include <map>
#include <set>
#include <fstream>
#include <vector>
#include <iostream>
class TextQuery
{
public:
class QueryResult;
using line_no = std::vector<std::string>::size_type;
TextQuery(std::ifstream&);
QueryResult query(const std::string&) const;
void display_map();
private:
std::shared_ptr<std::vector<std::string>> file;//输入文件
std::map<std::string, std::shared_ptr<std::set<line_no>>> wm;
static std::string cleanup_str(const std::string&);
};
class TextQuery::QueryResult
{
friend std::ostream& print(std::ostream&, const QueryResult&);
public:
typedef std::vector<std::string>::size_type line_no;
typedef std::set<line_no>::const_iterator line_it;
QueryResult(std::string s, std::shared_ptr<std::set<line_no>> p,
std::shared_ptr<std::vector<std::string>> f);
line_it begin() const { return lines->cbegin(); }
line_it end() const { return lines->cend(); }
std::shared_ptr<std::vector<std::string>> get_file() { return file; }
private:
std::string sought;//word this query represents
std::shared_ptr<std::set<line_no>> lines;//lines it's on
std::shared_ptr<std::vector<std::string>> file;//input file
};
std::ostream &print(std::ostream&, const TextQuery::QueryResult&);
TextQuery::QueryResult::QueryResult(std::string s, std::shared_ptr<std::set<line_no>> p, std::shared_ptr<std::vector<std::string>> f)
:sought(s), lines(p), file(f)
{
}
#endif // PROGRAM19_20_H
#include <sstream> //istringstream
#include "program19_20.h"
#include "make_plural.h"
#include <cstdlib> //for EXIT_FAILURE
using std::size_t;
using std::shared_ptr;
using std::istringstream;
using std::string;
using std::getline;
using std::vector;
using std::map;
using std::set;
using std::cerr;
using std::cout;
using std::cin;
using std::ostream;
using std::endl;
using std::ifstream;
using std::strlen;
using std::pair;
// read the input file and build the map of lines to line numbers
TextQuery::TextQuery(ifstream &is): file(new vector<string>)
{
string text;
while(getline(is, text)) // for each line in the file
{
file->push_back(text);// remember this line of text
unsigned long n = file->size() - 1;// the current line number
istringstream line(text); // separate the line into words
string word;
while(line >> word)
{
word = cleanup_str(word);
//if word isn't already in wm, subscripting adds a new entry
auto &lines = wm[word];//lines is a shared_ptr
if(!lines)//that pointer is null the first time we see word
{
lines.reset(new set<line_no>);// allocate a new set
}
lines->insert(n);// insert this line number
}
}
}
// not covered in the book -- cleanup_str removes
// punctuation and converts all text to lowercase so that
// the queries operate in a case insensitive manner
string TextQuery::cleanup_str(const string &word)
{
string ret;
for(auto it = word.begin(); it != word.end(); ++it)
{
if(!ispunct(*it))
{
ret += tolower(*it);
}
}
return ret;
}
TextQuery::QueryResult TextQuery::query(const string &sought) const
{
// we'll return a pointer to this set if we don't find sought
static shared_ptr<set<line_no>> nodata(new set<line_no>);
//use find and not a subscript to avoid adding words to wm!
auto loc = wm.find(cleanup_str(sought));
if(loc == wm.end())
{
return TextQuery::QueryResult(sought, nodata, file);
}
else
{
return TextQuery::QueryResult(sought, loc->second, file);
}
}
ostream &print(ostream &os, const TextQuery::QueryResult &qr)
{
//if the word was found, print the count and all occurrences
os << qr.sought << " occurs " << qr.lines->size() << " " << make_plural(qr.lines->size(), "time", "s") << endl;
// print each line in which the word appeared
for(auto num: *qr.lines)
{
// don't confound the user with text lines starting at 0
os << "\t(line " << num + 1 << ") " << *(qr.file->begin() + num) << endl;
}
return os;
}
// debugging routine, not covered in the book
void TextQuery::display_map()
{
auto iter = wm.cbegin(), iter_end = wm.cend();
//for each word in the map
for(; iter != iter_end; ++iter)
{
cout << "word: " << iter->first << " {";
// fetch location vector as a const reference to avoid copying it
auto text_locs = iter->second;
auto loc_iter = text_locs->cbegin(), loc_iter_end = text_locs->cend();
// print all line numbers for this word
while(loc_iter != loc_iter_end)
{
cout << *loc_iter;
if(++loc_iter != loc_iter_end)
cout << ", ";
}
cout << "}\n";// end list of output this word
}
cout << endl; // finished printing entire map
}
void runQueries(ifstream &infile)
{
//infile is an ifstream that is the file we want to query
TextQuery tq(infile); // store the file and build the query map
// iterate with the user: prompt for a word to find and print results
while(true)
{
cout << "enter word to look for, or q to quit:" << endl;
string s;
// stop if we hit end-of-file on the input or if a 'q' is entered
if(!(cin >> s) || s == "q")
break;
// run the query and print the results
print(cout, tq.query(s)) << endl;
}
}
int main(int argc, const char * argv[])
{
// open the file from which user will query words
ifstream infile;
// open returns void, so we use the comma operator XREF(commaOp)
// to check the state of infile after the open
if (argc < 2 || !(infile.open(argv[1]), infile)) {
cerr << "No input file!" << endl;
return EXIT_FAILURE;
}
runQueries(infile);
cout << "hello world===program exit " << endl;
return 0;
}
data19_20.txt文件内容如下:
Alice Emma has long flowing red hair.
Her Daddy says when the wind blows
through her hair, it looks almost alive,
like a fiery bird in flight.
A beautiful fiery bird, he tells her,
magical but untamed.
"Daddy, shush, there is no such thing,"
she tells him, at the same time wanting
him to tell her more.
Shyly, she asks, "I mean, Daddy, is there?"
设置命令行参数
运行:
|