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