宣告:

文中內容收集整理自《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::size_type;

TextQuery(ifstream&);

QueryResult Query(const string&) const;

private:

shared_ptr> m_spFile;

map>> m_vm;

}

在讀取文字時,我們把每一行的內容存起來,所以需要用到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> nodata(new set);

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::size_type;

TextQuery(std::ifstream&);

QueryResult Query(const std::string&) const;

private:

std::shared_ptr> m_spFile;

std::map>> m_vm;

};

class QueryResult

{

friend std::ostream& PrintResult(std::ostream&, const QueryResult&);

public:

using line_no = std::vector::size_type;

QueryResult(std::string s, std::shared_ptr> p, std::shared_ptr> f) :

sought(s), lines(p), file(f) {}

private:

std::string sought;

std::shared_ptr> lines;

std::shared_ptr> file;

};

#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> nodata(new std::set);

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小時並輸出筆記。

與其去羨慕高手裝逼,不如來見證菜鳥成長!