记录一下,这两个例子很棒。
文本查询程序
#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,因为在移动操作内部部分操作可能会抛出异常。