现在的位置: 首页 > 综合 > 正文

《c++ primer》文本查询程序和邮件处理程序

2019年05月18日 ⁄ 综合 ⁄ 共 6635字 ⁄ 字号 评论关闭

记录一下,这两个例子很棒。

文本查询程序

#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,因为在移动操作内部部分操作可能会抛出异常。

抱歉!评论已关闭.