《C++ Primer》讀書筆記-第十二章 03 使用標準庫 part1
聲明:
- 文中內容收集整理自《C++ Primer 中文版 (第5版)》,版權歸原書所有。
- 原書有更加詳細、精彩的釋義,請大家購買正版書籍進行學習。
- 本文僅作學習交流使用,禁止任何形式的轉載
正文
這一節給出了一個例子,將前面所學的內容串了起來。這簡直是太棒了!
如果在看這個例子的時候有任何模糊的地方,請往回翻,進行複習和鞏固。
整整一周我都在看這個例子,遇到前面的知識點記不清楚的地方就複習一下。
等到把整個程序都搞懂的時候,那簡直太嗨了。
剛好最近的課外讀物是《刻意練習》,理論和實踐相互印證,直讓人感覺到神奇,有種茅塞頓開的感覺。
好了,具體等到有時間另外寫一篇文章來說,今天先把這個程序的筆記寫一寫。
示例是一個文本查詢程序,類似於nodepad++等文本編輯器的查詢功能。之前也一直好奇這些編輯器的查詢是怎麼做到的,該例給出了一個思路。
遍歷文本中的單詞,將每一個單詞出現的行號記錄下來,形成一個map。使用set來記錄每個單詞出現的行號,可以避免重複。
定義了兩個類來完成功能:
- TextQuery職責是讀取、記錄和查詢
- QueryResult是一種數據結構,用來返回查詢結果
書中指出:當我們設計一個類時,在真正實現成員之前先編寫程序使用這個類,是一種非常有用的方法。通過這種方法,可以看到類是否具有我們所需要的操作。
這個我理解有點測試驅動開發的意思:先把測試代碼寫好,再去寫功能代碼,如果功能代碼能使測試用例全部通過,則說明開發符合預期。利弊分析如下:
- 優勢:當需要對功能代碼做出優化等變更時,不會引起功能回退。因為始終要保證測試用例全部通過。
- 弊端:測試用例需要詳細全面的設計,需要花上一些時間。
回到書上的觀點,這裡只是驗證我們設計的類是否具有所需要的操作,也是極好的。可以在以後的工作中試一試。
void runQueries(ifstream &infile) n{ n TextQuery tq(infile); n while(true) n { n cout << "enter word to look for, or q to quit: "; n string s; n if(!(cin>>s) || s == q) n { n break; n } nn print(cout, tq.query(s)) << endl; n } n}n
從上面的代碼中,至少可以得到以下幾條信息:
- TextQuery類的構造函數接受一個ifstream
- TextQuery有一個query成員函數,接受一個string,返回QueryResult
- print的入參分別是ostream和QueryResult,返回ostream
- 其它地方沒有看到讀取文本內容的代碼,判斷是在TextQuery的構造函數中完成
TextQuery類的定義
class QueryResult; nclass TextQuery n{ npublic: n using line_no = vector<string>::size_type; n TextQuery(ifstream&); n QueryResult Query(const string&) const; nprivate: n shared_ptr<vector<string>> m_spFile; n map<string, shared_ptr<set<line_no>>> m_vm; n}n
在讀取文本時,我們把每一行的內容存起來,所以需要用到vector<string>。
而在遍歷每個單詞的過程中,把單詞所在的行號記錄到一個set中,有助於我們實現查詢的功能。構造函數的實現
TextQuery::TextQuery(ifstream &is):m_spFile(new vector<string>) n{ n string sText; n while(getline(is, sText)) n { n m_spFile->push_back(sText); n int n = m_spFile->size() - 1; n istringstream line(sText); n string sWord; n while(line >> sWord) n { n auto &lines = m_vm[sWord]; n if( !lines ) n { n lines.reset(new set<line_no>); n } n lines->insert(n); n } n } n}n
構造函數讀取文本的內容,並把每一個單詞出現的行號保存到一個map中便於查詢,把每一行的內容存到一個vector中便於列印。
這樣查詢程序就很好寫了
QueryResult TextQuery::Query(const string &sought) const n{ n static shared_ptr<set<line_no>> nodata(new set<line_no>); n auto loc = m_vm.find(sought); n if( loc == m_vm.end() ) n { n return QueryResult(sought, nodate, file); n } n else n { n return QueryResult(sought, loc->second, file); n } n}n
這裡有兩個疑問:
- TextQuery的成員為什麼使用shared_ptr
- Query函數中nodata為什麼使用局部靜態變數
我們先打開visual studio把程序跑起來。下面是完整代碼
//TextQuery.hnn#pragma oncenn#ifndef TEXTQUERY_H_n#define TEXTQUERY_H_nn#include "stdafx.h"n#include <vector>n#include <string>n#include <istream>n#include <memory>n#include <map>n#include <set>nnclass QueryResult;nclass TextQueryn{npublic:n using line_no = std::vector<std::string>::size_type;n TextQuery(std::ifstream&);n QueryResult Query(const std::string&) const;nprivate:n std::shared_ptr<std::vector<std::string>> m_spFile;n std::map<std::string, std::shared_ptr<std::set<line_no>>> m_vm;n};nnclass QueryResultn{n friend std::ostream& PrintResult(std::ostream&, const QueryResult&);npublic:n using line_no = std::vector<std::string>::size_type;n QueryResult(std::string s, std::shared_ptr<std::set<line_no>> p, std::shared_ptr<std::vector<std::string>> f) :n sought(s), lines(p), file(f) {}nprivate:n std::string sought;n std::shared_ptr<std::set<line_no>> lines;n std::shared_ptr<std::vector<std::string>> file;n};nn#endifn
實現類
//TextQuery.cppnn#include "stdafx.h"n#include "TextQuery.h"n#include <istream>n#include <string>n#include <sstream>n#include <fstream>n#include <iostream>nnstd::ostream &PrintResult(std::ostream &os, const QueryResult &qr)n{n os << qr.sought << " occurs " << qr.lines->size() << " " << "time(s)" << std::endl;n for (auto num : *qr.lines)n {n os << "t(line " << num + 1 << ") "n << *(qr.file->begin() + num) << std::endl;n }nn return os;n}nnTextQuery::TextQuery(std::ifstream &is) :m_spFile(new std::vector<std::string>)n{n std::string sText;n while (getline(is, sText))n {n m_spFile->push_back(sText);n int n = m_spFile->size() - 1;n std::istringstream line(sText);n std::string sWord;n while (line >> sWord)n {n auto &lines = m_vm[sWord];n if (!lines)n {n lines.reset(new std::set<line_no>);n }n lines->insert(n);n }n }n}nnQueryResult TextQuery::Query(const std::string &sought) constn{n static std::shared_ptr<std::set<line_no>> nodata(new std::set<line_no>);n auto loc = m_vm.find(sought);n if (loc == m_vm.end())n {n return QueryResult(sought, nodata, m_spFile);n }n elsen {n return QueryResult(sought, loc->second, m_spFile);n }n}n
主函數
//main.cppnn#include "stdafx.h"n#include "TextQuery.h"n#include <iostream>n#include <fstream>n#include <string>nnvoid runQueries(std::ifstream &infile)n{n TextQuery tq(infile);n while (true)n {n std::cout << "enter word to look for, or q to quit: ";n std::string s;n if (!(std::cin >> s) || s == "q")n {n break;n }nn PrintResult(std::cout, tq.Query(s)) << std::endl;n }n}nnint main()n{n std::ifstream infile("F:myprojectpythonTemplateEngineTemplite.py");n runQueries(infile);nn return 0;n}n
今天太晚了,先寫到這裡。我準備把shared_ptr去掉試一下。大家可以按照這個思路做個測驗。
END
微信公眾號, 馬志峰的編程筆記
專註做好一件事,每天早起學習編程1.5小時並輸出筆記。
與其去羨慕高手裝逼,不如來見證菜鳥成長!
推薦閱讀:
※【源碼眾讀】之每日問答,Day1
※基於現代C++的四則運算語法分析器(上)
※【源碼眾讀】之問題解答,Part_8
※《C++ Primer》讀書筆記-第十二章 03 使用標準庫 part2
※《C++ Primer》讀書筆記-第七章 04 類的作用域
TAG:C |
