记录一下,这两个例子很棒。
文本查询程序
#ifndef _TEXTQUERY_H_ #define _TEXTQUERY_H_ #include <iostream> #include <fstream> #include <sstream> #include <memory> #include <string> #include <vector> #include <map> #include <set> using line_no = std::vector<std::string>::size_type; class TextQuery; class QueryResult; class QueryResult { friend class TextQuery; friend std::ostream& print(std::ostream &os, const QueryResult &qr); public: QueryResult(std::string s, std::shared_ptr<std::set<line_no>>l, std::shared_ptr<std::vector<std::string>> f): s_word(s),lines(l),file(f) { } private: std::string s_word; std::shared_ptr<std::set<line_no>>lines; std::shared_ptr<std::vector<std::string>>file; }; class TextQuery { friend class QueryResult; public: TextQuery() = default; TextQuery(std::ifstream &infile); QueryResult query(const std::string&)const; private: std::shared_ptr<std::vector<std::string>>m_file; std::map<std::string, std::shared_ptr<std::set<line_no>>>m_word_line; }; #endif
#include "TextQuery.h" TextQuery::TextQuery(std::ifstream &infile):m_file(new std::vector<std::string>)//make_shared<vector<string>>() { std::string line; std::string word; static int i = 0; //t_file = make_shared<vector<string>>; while(std::getline(infile,line)) { i++; m_file->push_back(line);//按行保存文本. std::istringstream i_line(line); while(!i_line.eof()) { i_line >> word; auto &li = m_word_line[word]; if(!li) //为了避免拷贝set行号动态分配 li.reset(new std::set<line_no>); li->insert(i); } } } QueryResult TextQuery::query(const std::string& sought)const { <span style="color:#FF0000;">static std::shared_ptr<std::set<line_no>>nodata(new std::set<line_no>); </span> auto loc = m_word_line.find(sought); if(loc == m_word_line.end()) return QueryResult(sought, nodata, m_file); else return QueryResult(sought, loc->second, m_file); } std::ostream& print(std::ostream &os, const QueryResult &qr) { os << "element occurs " << qr.lines->size() << " times" << std::endl; for(line_no i : *qr.lines) { os << " " << "(line " << i+1 << ") "; os << *(qr.file->begin()+i)<< std::endl; } return os; }
#include "TextQuery.h" int main(int argc, char *argv[]) { std::ifstream is(argv[1]); TextQuery essay(is); std::string word; std::cout << "input search word('q' is quit):"; while(std::cin >> word && word != "q") { std::cout << std::endl; print(std::cout, essay.query(word)); std::cout << "input search word('q' is quit):"; } }
注意!:
1.对于可能置于头文件的中的代码,在使用标准库名字时要加上std::
头文件不应该使用using声明,
位于头文件代码一般来说不应该使用using声明,因为头文件的内容会拷贝到每个引用它的文件中去,如果某个头文件有using 声明,那么引用它的每个
头文件都会有using声明,对于某些程序来说,由于不经意间包含了某些名字,可能会出现名字冲突
2.查询时千万不能用map的[ ]操作符,若不存在的话会生成,那么查询就没意义了,所以应该query定义成const成员函数,不允许添加,避免[ ]。可以使用find
3.代码中的static shared_ptr<set<string>>nodata(new set<string>), static成员无论调用多少次,只在第一次时执行初始化,很好的方法。
如果new的话每次用都会new。
邮件处理程序
/* * Message类: * 消息类,可以存储或删除 * 一个Message可以属于多个Floder */ #ifndef _MESSAGE_H_ #define _MESSAGE_H_ #include <iostream> #include <set> #include <memory> #include <string> #include "Folder.h" class Message; class Folder; class Message { friend void swap(Message &lhs, Message &rhs); friend std::istream& read(std::istream &in, Message &msg); friend std::ostream& print(std::ostream &os, Message &msg); friend class Folder; public: //隐式初始化为空,且避免隐式转换 explicit Message(const std::string &s = " "): contents(s) { } Message(const Message &msg); //赋值形参,add Message(Message &&msg); //移动拷贝 Message& operator=(const Message &msg);//删除左值message,赋值右值add 三个拷贝控制成员都有交叉操作,所以定义private Message& operator=(Message &&msg); //移动赋值 ~Message(); //删除message 工具函数来处理,避免代码重复。提高效率 //两个成员函数,从floders保存和删除message void save(Folder &f); void remove(Folder &f); private: std::string contents; //message text std::set<Folder*>folders; //message from floders 每个message包含多个指向floders的指针,指明它属于哪些floders void add_to_Folders(const Message &msg); void remove_from_Folders(); }; #endif
#include "Message.h" void Message::save(Folder &f) { folders.insert(&f); //message保存到flod,message的floder添加f f.addMsg(this); //floder里面要add message } void Message::remove(Folder &f) { folders.erase(&f); f.rmMsg(this); } //添加信息message,要对于每个包含message的添加message void Message::add_to_Folders(const Message &msg) { for(auto &f : msg.folders) f->addMsg(this); } void Message::remove_from_Folders() { //自己保存的每个floder删除自己 for(auto &f : folders) f->rmMsg(this); } //拷贝构造函数 Message::Message(const Message &msg):contents(msg.contents),folders(msg.folders) { add_to_Folders(msg); } //赋值操作符 Message& Message::operator=(const Message &msg) { remove_from_Folders(); contents = msg.contents; folders = msg.folders; add_to_Folders(msg); return *this; } Message::~Message() { remove_from_Folders(); } std::istream& read(std::istream &in, Message &msg) { in >> msg.contents; return in; } std::ostream& print(std::ostream &os, Message &msg) { os << "Message:" << msg.contents << "\n"; os << "Folders:"; for(auto f : msg.folders) os << f->fold_name << " "; os << "\n"; return os; } void swap(Message &lhs, Message &rhs) { using std::swap; for(auto f : lhs.folders) f->rmMsg(&lhs); for(auto f : rhs.folders) f->rmMsg(&rhs); swap(lhs.folders, rhs.folders); swap(lhs.contents, rhs.contents); for(auto f : lhs.folders) f->addMsg(&lhs); for(auto f : rhs.folders) f->addMsg(&rhs); } Message::Message(Message &&msg) //这两个函数可以有很多共有操作,可以换成一个私密函数来简化 { contents = std::move(msg.contents); folders = std::move(msg.folders); for(auto f : folders) { f->rmMsg(&msg); f->addMsg(this); } msg.folders.clear(); } Message& Message::operator=(Message &&msg) { if(this != &msg) { remove_from_Folders(); contents = std::move(msg.contents); folders = std::move(msg.folders); for(auto f : folders) { f->rmMsg(&msg); f->addMsg(this); } msg.folders.clear(); } return *this; }
Folder
#ifndef _FOLDER_H_ #define _FOLDER_H_ #include <iostream> #include <set> #include <string> class Folder; class Message; class Folder { friend std::istream& read(std::istream &in, Message &msg); friend std::ostream& print(std::ostream &os, Message &msg); friend class Message; public: Folder(const std::string &s = " "): fold_name(s) { } ~Folder() { } void addMsg(Message *msg); //删除message void rmMsg(Message *msg); //添加message private: std::set<Message*>_fold; //保存message的flod std::string fold_name; }; #endif
#ifndef _FOLDER_H_ #define _FOLDER_H_ #include <iostream> #include <set> #include <string> class Folder; class Message; class Folder { friend std::istream& read(std::istream &in, Message &msg); friend std::ostream& print(std::ostream &os, Message &msg); friend class Message; public: Folder(const std::string &s = " "): fold_name(s) { } ~Folder() { } void addMsg(Message *msg); //删除message void rmMsg(Message *msg); //添加message private: std::set<Message*>_fold; //保存message的flod std::string fold_name; }; #endif
main函数
#include "Folder.h" #include "Message.h" int main() { Folder file1("mail1"); Folder file2("mail2"); Message m1; Message m2; read(std::cin, m1); m1.save(file1); m1.save(file2); read(std::cin, m2); m2.save(file1); m2.save(file2); print(std::cout, m1); print(std::cout, m2); swap(m1,m2); print(std::cout, m1); print(std::cout, m2); }
!注意:
在类内如果有多个函数重复几个操作,我们可以把这些操作定义在private,作为工具函数来调用。
如果要避免隐式转换,我们应该显示的写出关键字explicit
函数名字和变量名字起的要符合实际作用
析构函数如果使用默认记得加上=defalut,自己定义要加{ }
思路清晰在开始写代码,尽量避免代码重复。
新添加的移动操作没有在末尾添加noexcept,因为在移动操作内部部分操作可能会抛出异常。