• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

c++primer的textquery例子。

原作者: [db:作者] 来自: [db:来源] 收藏 邀请

总共3种方法,一种是第四版书上的面向对象的教学方法。一种是实际中应该使用的简洁方法。一种是模板的方法。

1)第四版书中,面向对象的方法,基类,继承,多态

2)自己的更简洁的写法。(前提条件:如果不需要打印出表达式,仅仅计算结果)

3)自己的模板模拟多态的方法。

 

 

////////////////模板的方法/////////////////////////////////////////////////////////////////

第三种写法:利用模板模拟多态。

了解模板后,看到STL的迭代器的实现。发现模板也可以模拟多态。试了下,用模板写。感觉舒服多了。不用先写好基类和继承类。可以更自由的实现多态。

但模板会导致代码膨胀。比如

template<typename LT,typename RT>
class AndQuery
{
private:
    LT left;
    RT right;
}

 每次模板参数类型不一样。就会导致一个新的类的定义。(应该编译器会产生一些比如 xxxaaa_andquery 的class类。)应该是随着表达式的逻辑符号,增加一个就生成一个新类。

模板函数也是一样。根据参数类型的不一样。生成几份函数,就相当于重载。

 

#include <iostream>
#include <vector>
#include <set>


using namespace std;

class searchC
{
public:
    searchC(const vector<string>* p):content(p){}
    set<int> query(const string& key)
    {
        set<int> ret;
        int linesCount=content->size();
        for(int i=0;i!=linesCount;++i)
        {
            string linec=(*content)[i];
            if(linec.find(key)!=string::npos)
            {
                ret.insert(i+1);
            }
        }
        return ret;
    }
private:
     const vector<string>* content;
};

class Query{
public:
    Query(const string& _key);
    set<int> GetRnt();
    static searchC sc;
    static int count_lines;
private:
    Query();
    string key;
};

Query::Query(const string& _key):key(_key){}
set<int> Query::GetRnt()
{
    set<int> rnt= sc.query(key);
    return rnt;
}


//template//////////////////////////////////////
template<typename LT,typename RT>
class AndQuery
{
public:
    AndQuery(const LT& _left,const RT& _right):left(LT(_left)),right(RT(_right)){}
    set<int> GetRnt()
    {
        set<int> _ret;
        set<int> leftret=left.GetRnt();
        set<int> rightret=right.GetRnt();
        set<int>::const_iterator cit=leftret.begin();
        for(cit;cit!=leftret.end();++cit)
        {
            if(rightret.find(*cit)!=rightret.end())
            {
                _ret.insert(*cit);
            }
        }

        return _ret;
    }
private:
    LT left;
    RT right;
};

//template//////////////////////////////////////
template<typename LT,typename RT>
class OrQuery
{
public:
    OrQuery(const LT& _left,const RT& _right):left(LT(_left)),right(RT(_right)){}
    set<int> GetRnt()
    {
        set<int> leftret=left.GetRnt();
        set<int> rightret=right.GetRnt();
        leftret.insert(rightret.begin(),rightret.end());

        return leftret;
    }
private:
    LT left;
    RT right;
};


template<typename LT>
class NotQuery
{
public:
    NotQuery(const LT& _left):left(LT(_left)){}
    set<int> GetRnt()
    {


        set<int> _ret;
        set<int> leftret=left.GetRnt();
        for(int i=1;i!=Query::count_lines+1;++i)
        {
            if(leftret.find(i)==leftret.end())
            {
                _ret.insert(i);
            }
        }
        return _ret;


        return leftret;
    }
private:
    LT left;
};


template<typename T1,typename T2>
AndQuery<T1,T2> operator&(const T1& _left,const T2& _right)
{
    return AndQuery<T1,T2>(_left,_right);
}

template<typename T1,typename T2>
OrQuery<T1,T2> operator|(const T1& _left,const T2& _right)
{
    return OrQuery<T1,T2>(_left,_right);
}

template<typename T1>
NotQuery<T1> operator!(const T1& _left)
{
    return NotQuery<T1>(_left);
}


//main/////////////////////

searchC Query::sc(0x0);
int Query::count_lines=0;
int main()
{
    vector<string> context;
    context.push_back("little start.");
    context.push_back("a apple.");
    context.push_back("two apple.");
    context.push_back("dog");
    context.push_back("two dog.");
    context.push_back("good dog");

    searchC myQuery(&context);
    Query::sc=myQuery;
    Query::count_lines=context.size();


    auto myQ=!(Query("dog")&Query("two")|Query("little"));
    set<int> rnt= myQ.GetRnt();
    set<int>::iterator itrt=rnt.begin();
    for(int i=0;i!=rnt.size();++i)
    {
        cout<<*(itrt++)<<endl;
    }

    return 0;
}

 

 

 

 

 

××××××××××××××××××××仅仅计算结果的简单方法××××××××××××××××××××××××

这是假定不需要打印出计算表达式的前提下。要打印的话,就必须树形结构保存数据之间的关系。

 

如果只需要计算机结果,发现原来有很简单的做法。不需要继承,不需要new和delete。并且表达式也是一样的简单:Query node= !(!Query("two")|Query("dog")&Query("good"));

继承的目的就是方法的多态。运行时才能知道到底调用的是那个方法。这是继承的魅力所在。

但是如果问题本身,可以不需要运行时去多态呢。编译时就把方法确定下来呢?

如这里。Query("two")就是生成一个node对象,对象包含一个成员变量,就是结果ret。

Query("dog")&Query("good") 也是生成一个node对象。构造对象的时候。立马把结果放入构造函数.

问题就立马解决了。

而不需要让Query("dog")&Query("good") 生成一个对象。对象又包含2个子对象的指针。要到调用求结果的方法时,才去调用子对象的求结果方法(多态)。

如果不是因为 操作符必须需要至少一个对象。连类都可以省去了。直接一个function方法就可以了。 如 set<int> ret=function("two")|function("dog");

不过这里居于一个事实,就是临时对象。Query node= !(!Query("two")|Query("dog")&Query("good"));

不管你继不继承,这个表达式都会生成5个临时对象。编译器编译期间已经预留了栈内存给他们。应该赋值给左值node之后。就会调用它们的析构了。

所以用继承,多态,就必须用new,来保存对象的指针,从而到时候调用对象的方法。 而我们这里,每步已经求出没步的结果。所以不需要继承,不需要new和delete。 

mian.cpp

 

searchC Query::sc(0x0);
int Query::count_lines=0;


void
main_textquery() { vector<string> context; context.push_back("little start."); context.push_back("a apple."); context.push_back("two apple."); context.push_back("dog"); context.push_back("two dog."); context.push_back("good dog"); searchC myQuery(&context); Query::sc=myQuery; Query::count_lines=context.size(); Query node= !(!Query("two")|Query("dog")&Query("good")); set<int> ret=node.getRet(); set<int>::const_iterator cit=ret.begin(); for(cit;cit!=ret.end();++cit) { cout<<*cit<<endl; } }

 

 

 

textquery.h

#ifndef TEXTQUERY_H_INCLUDED
#define TEXTQUERY_H_INCLUDED
#include <set>
#include <vector>


using namespace std;

class searchC
{
public:
    searchC(vector<string>* p):content(p){}
    set<int> query(const string& key)
    {
        set<int> ret;
        int linesCount=content->size();
        for(int i=0;i!=linesCount;++i)
        {
            string linec=(*content)[i];
            if(linec.find(key)!=string::npos)
            {
                ret.insert(i+1);
            }
        }
        return ret;
    }
private:
    vector<string>* content;
};


class Query{
public:
    Query(const string& _key);
    Query(const set<int>&);
    set<int> getRet();
    static searchC sc;
    static int count_lines;
private:

    Query();
    set<int> ret;

friend Query operator|(const Query& lht,const Query& rht);
friend Query operator&(const Query& lht,const Query& rht);
friend Query operator!(const Query& lht);
};

Query operator&(const Query& lht,const Query& rht);

Query::Query(const string& _key)
{
    ret=sc.query(_key);
}

Query::Query(const set<int>& _ret):ret(_ret){}

Query operator|(const Query& lht,const Query& rht)
{
    set<int> _ret;
    _ret=lht.ret;
    _ret.insert(rht.ret.begin(),rht.ret.end());
    return Query(_ret);
}

Query operator!(const Query& lht)
{
    set<int> _ret;
    set<int> leftset=lht.ret;
    for(int i=1;i!=Query::count_lines+1;++i)
    {
        if(leftset.find(i)==leftset.end())
        {
            _ret.insert(i);
        }
    }
    return Query(_ret);
}


Query operator&(const Query& lht,const Query& rht)
{
    set<int> _ret;
    set<int> leftret=lht.ret;
    set<int> rightret=rht.ret;

    set<int>::const_iterator cit=leftret.begin();
    for(cit;cit!=leftret.end();++cit)
    {
        if(rightret.find(*cit)!=rightret.end())
        {
            _ret.insert(*cit);
        }
    }

    return Query(_ret);
}

set<int> Query::getRet()
{
    return ret;
}

#endif // TEXTQUERY_H_INCLUDED

 

 

 

 

 

 

**********************************************************第一次的做,书中方法×××××××××××××××××××××××××××××××××××××××××

 c++ primer 的 textquery 例子,做了好几天。发现对入门c++基础是个很大检测,不像初看时,那么简单。

起码包含了几个知识点,智能指针,值类型智能指针,树的遍历(递归),构造和析构,多态,操作符重载。

1)编译器根据符号优先级(c++的文法句子),对方法的执行是一个树的遍历过程。所以我们最后我们得到的结果是一个树的根。如,Query tmp=~(Query(star)|Query(little)&Query(Twinkle)); tmp 是树的根节点。

2)用后续遍历法执行每个节点的eval方法。来模拟 编译器对表达式的计算思路。但仔细看的话,会知道方法的执行和当初节点的建立顺序其实不是一样的。不过不妨碍结果。

3)display的过程是一个树中序遍历的过程。

 

 完整下载 ,ide:code block.

 

部分代码,方便快速查看。

textquery.h

#ifndef TEXTQUERY_H_INCLUDED
#define TEXTQUERY_H_INCLUDED

#include "head.h"

typedef vector<string>::size_type line_no;
typedef map<string,set<line_no> >::iterator Type_mIt;
typedef set<line_no>::iterator Type_sIt;

class TextQuery
{
public:
    TextQuery(){}

    void readfile(ifstream &is)
    {
        store_file(is);
        build_map();
    }

    set<line_no> run_query(const string& word) const
    {
        return word_map.find(word)->second;
    }

    string text_line(line_no line_n) const
    {
        if(line_n<=lines_of_text.size())
        {
            return lines_of_text[line_n];
        }
        else
        {
            throw string("out of range!");
        }
    }

    map<string,set<line_no> >& getmap()
    {
        return word_map;
    }
    int getsumLine()const
    {
        return lines_of_text.size();
    }

    set<line_no> getAllset()const
    {
        set<line_no> tmp;
        for(line_no i=0;i!=lines_of_text.size();++i)
        {
            tmp.insert(i);
        }
        return tmp;
    }

    ~TextQuery()
    {

    }

private:
//data
    vector<string> lines_of_text;
    map<string,set<line_no> > word_map;

//text
    void store_file(ifstream& is)
    {
        string textLine;
        if (!is.is_open())
        {cout << "Error opening file";}
        while (getline(is,textLine))
        {
            lines_of_text.push_back(textLine);
        }
    }

    void build_map()
    {
        for(line_no i=0;i!= lines_of_text.size();i++)
        {
            istringstream words(lines_of_text[i]);
            string word;
            while(words >> word)
            {
                word_map[word].insert(i);
                word="";
            }
        }
    }
};

#endif // TEXTQUERY_H_INCLUDED

 

head.h

#ifndef HEAD_H_INCLUDED
#define HEAD_H_INCLUDED
//标准库--》类型缩写--》类定义--》cpp文档,函数申明--》 通用函数。--》其他函数。

#include <set>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <iostream>
#include <fstream>
#include <cctype>
#include <cstring>
#include <sstream>
#include <algorithm>
using namespace std;

typedef vector<string>::size_type line_no;



//main.cpp
void linkqureyf2();
void linkqureyf();
void simQuery();
void textquery();
void opqueryF();
void outLine(ostream& of,const string &content);
void print_result(const map<string,set<line_no> >& wordsLine);
void print_result2(const set<line_no> &wordsLine);
void treefun();

//simple
set<line_no> OrSet(const set<line_no>& ls,const set<line_no>& rs);
set<line_no> AndSet(const set<line_no>& ls,const set<line_no>& rs);
set<line_no> NotSet(const set<line_no>& sourceSet,const set<line_no>& AllSet);

#endif // HEAD_H_INCLUDED

 

main.cpp

#include "head.h"
#include "textquery.h"
#include "simplequery.h"
#include "opquery.h"
#include "LinkQuery.h"
#include "lineLinkQuery.h"
#include "TreeQuery.h"

vector<u_p> LinkQuery::funs=vector<u_p>();
bool Query::debug=false;
int main()
{
    //textquery();
    //simQuery();
    //opqueryF();
    //linkqureyf();
    treefun();
    return 0;
}
//依据表达式用最恰当的树的数据结构,来储存实例。建立树。
//采用后序遍历法,访问每个节点,执行方法,来达到表达式同样的结果(尽管顺序其实不是严格一致)。

void treefun()
{
    ifstream infile("littlestar.txt");
    TextQuery file;
    file.readfile(infile);

    outLine(cout,"words-lineNo mapping.....................");
    print_result(file.getmap());
    string little="little";
    string Twinkle="Twinkle";
    string star="star";

    Query tmp=~(Query(star)|Query(little)&Query(Twinkle));

    cout<<tmp.NodeName()<<endl;
    cout<<tmp.display(cout)<<endl;
    print_result2(tmp.Eval(file));


}
void textquery()
{
    ifstream infile("littlestar.txt");
    TextQuery file;
    file.readfile(infile);

    outLine(cout,"words-lineNo mapping.....................");
    print_result(file.getmap());
    set<line_no> ret= file.run_query("little");
    outLine(cout,"'little line-no:'.....................");
    print_result2(ret);
}


void outLine(ostream& of,const string &content)
{
    of<<"***********"<<content<<"***********"<<endl;
}

void print_result(const map<string,set<line_no> >& wordsLine)
{
    map<string,set<line_no> >::const_iterator beg1;
    for(beg1=wordsLine.begin();beg1!=wordsLine.end();beg1++)
    {
        cout<<beg1->first<<":";
        set<line_no>::iterator bega=beg1->second.begin();
        for(line_no i=0;i<beg1->second.size();i++,bega++)
        {
            cout<<*bega+1<<",";
        }
        cout<<endl;
    }
}

void print_result2(const set<line_no> &wordsLine)
{
    set<vector<string>::size_type>::iterator beg=wordsLine.begin();
    while(beg!=wordsLine.end())
    {
        cout<<*beg+1<<",";
        ++beg;
    }
    cout<<endl;
}

treequery.h

#ifndef TREEQUERY_H_INCLUDED
#define TREEQUERY_H_INCLUDED
#include "head.h"
#include "textquery.h"

//base class
//所有方法,数据都private,让handle为友类访问,操作符重载方法也访问。
//注意看构造函数,//所以const 和&,需要认真理解,完成例子后,再用时间熟悉下const。
class Query;
ostream& operator<<(ostream &os, const Query& q);
Query operator&(const Query& lhs,const Query& rhs);
Query operator|(const Query& lhs,const Query& rhs);
Query operator~(const Query& lhs);

class base_TNode
{
protected:
    virtual ~base_TNode();
private://方法全部隐藏,且虚函数。由handle class来代理,并根据实际对象,调用自己的。
    virtual set<line_no> Eval(const TextQuery& _file)=0;
    virtual string NodeName()const=0;//因为此方法会被派生类的数据成员lhsrhs调用。 而Node_2L,和notnode中的数据成员lhs,rhs,都为const。所以这里要const。
    virtual ostream& display(ostream& os)const=0;//同上。


friend class Query;
friend Query operator&(const Query& lhs,const Query& rhs);
friend Query operator|(const Query& lhs,const Query& rhs);
friend Query operator~(const Query& lhs);
};

base_TNode::~base_TNode(){}

//handle class,有base_TNode,基类的指针成员。
//作为功能之一:智能指针,所有使用基类指针的地方,必须使用Query。以便计数器正确。
//作为功能之二,handle。handle class 必须代理派生类方法。
class Query
{
public:

    Query(const Query& up);
    Query& operator=(const Query& up);
    ~Query();

    Query(const string& _word);
    set<line_no> Eval(const TextQuery& _file)const;
    string NodeName() const;//连派生类访问基类的方法。都要通过handle class。
    ostream& display(ostream& os)const;


    //ostream & operator<<(const Query& _qy);

    static bool debug;

private:
    Query(base_TNode* _p);//仅仅给操作符重载使用,隐藏,把操作符重载方法,加为友元。
    base_TNode* p;//必须隐藏指针,基类的方法都由handle class。代理。
    unsigned int * use;
    void del();

friend  Query operator|(const Query& lhs,const Query& rhs);
friend  Query operator&(const Query& lhs,const Query& rhs);
friend  Query operator~(const Query& lhs);
};


//leaf
class Leaf:public base_TNode
{
private:
    Leaf(const string& _word);//隐藏派生类,只给handle class 友类来访问。
    string NodeName()const;
    string word;
    set<line_no> Eval(const TextQuery&);
    ostream& display(ostream& os)const;
friend class Query;
};
//friend Query::Query(base_TNode* _p);
Leaf::Leaf(const string& _word):word(_word){}
string Leaf::NodeName()const
{
    return word;
}
set<line_no> Leaf::Eval(const TextQuery& _file)
{
    //if(no left child and no right child)
    //看成后序遍历的,递归终结的临界点。
    return _file.run_query(word);
}

ostream& Leaf::display(ostream& os)const
{
    return os<<word;
}


//base of 2-child node
class Node_2L:public base_TNode
{
protected:
    Node_2L(Query _lhs, Query _rhs,const string & _opstr);//参数值传递Query,(handle class) 对象。这样构造的时候,会对lhs,rhs进行直copy。
    //直copy会引发lhs,rhs中,自己的lhs,rhs直copy。一层一层。如此引用型计数器use,才能正常得到引用次数。临时对象析构时,才不会delete handle class,所指向的对象。
    
                      

鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
ffmpeg遇到inttypes.h和UINT64_C发布时间:2022-07-14
下一篇:
C#中保存GIF文件后透明背景问题的一个解决方法发布时间:2022-07-14
热门推荐
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap