zoukankan      html  css  js  c++  java
  • c++ primer 的 textquery 例子。

    总共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,所指向的对象。
        const Query  lhs;
        const Query  rhs;
        ostream& display(ostream& os)const;
    private:
        string NodeName()const;
    
        string opstr;
    };
    Node_2L::Node_2L(Query _lhs, Query _rhs,const string & _opstr):lhs(_lhs),rhs(_rhs),opstr(_opstr){}
    string Node_2L::NodeName()const
    {
        return "("+lhs.NodeName()+opstr+rhs.NodeName()+")";
    }
    
    ostream& Node_2L::display(ostream& os)const
    {
        //按照简单的下面方式得不到正确结果,会把lhs.display(os)当成一个地址打出来。
        //用简单方法,更容易维护。比如用NodeName方法同样的效果。那就必须重新解释<<的含义。重载<<。
        //return os<<"("<<lhs.display(os)<<opstr<<rhs.display(os)<<")";
         return os << "(" << lhs  << " " << opstr << " "<< rhs << ")";
    }
    
    //and node
    class AndNode:public Node_2L
    {
    private:
        AndNode( Query _lhs, Query _rhs);
        set<line_no> Eval(const TextQuery& _file);
    
    friend  Query operator&(const Query& lhs,const Query& rhs);//操作符重载需要访问。
    };
    AndNode::AndNode(Query _lhs, Query _rhs):Node_2L(_lhs,_rhs,"&"){}
    
    set<line_no> AndNode::Eval(const TextQuery& _file)
    {
        set<line_no> leftret=lhs.Eval(_file);
        set<line_no> rightret=rhs.Eval(_file);
        return AndSet(leftret,rightret);
    }
    
    
    
    //or node
    class OrNode:public Node_2L
    {
    private:
        OrNode( Query _lhs, Query _rhs);
        set<line_no> Eval(const TextQuery& _file);
    
    friend  Query operator|(const Query& lhs,const Query& rhs);//操作符重载需要访问。
    };
    OrNode::OrNode( Query _lhs, Query _rhs):Node_2L(_lhs,_rhs,"|"){}
    
    set<line_no> OrNode::Eval(const TextQuery& _file)
    {
        set<line_no> leftret=lhs.Eval(_file);
        set<line_no> rightret=rhs.Eval(_file);
        return OrSet(leftret,rightret);
    }
    
    
    //not node
    class NotNode:public base_TNode
    {
    private:
        NotNode(Query lhs);
        set<line_no> Eval(const TextQuery& _file);
        ostream& display(ostream& os)const;
        string NodeName()const;
        const Query lhs;
    friend  Query operator~(const Query& lhs);
    };
    
    NotNode::NotNode(Query _lhs):lhs(_lhs){}
    string NotNode::NodeName()const
    {
        return "~("+lhs.NodeName()+")";
    }
    
    set<line_no> NotNode::Eval(const TextQuery& _file)
    {
        set<line_no> leftret=lhs.Eval(_file);
        return NotSet(leftret,_file.getAllset());
    }
    
    ostream& NotNode::display(ostream& os)const
    {
        ////???????????????????????
        return os << "~(" << lhs << ")";
    }
    
    
    //定义
    Query::Query(base_TNode * _p):p(_p),use(new unsigned int(1)){if(Query::debug){cout<<p->NodeName()<<":  '*p' constr to query:"<<p<<"     use:."<<*use<<endl;}}
    
    Query::Query(const Query& up)
    {
        p=up.p;
        use=up.use;
        ++*use;
        if(Query::debug){cout<<p->NodeName()<<": ref:"<<p<<"     use:."<<*use<<endl;}
    }
    
    Query& Query::operator=(const Query& up)
    {
        ++*up.use;
        del();
        p=up.p;
        use=up.use;
        if(Query::debug){cout<<p->NodeName()<<": copy =:"<<p<<"     use:."<<*use<<endl;}
        return *this;
    }
    Query::~Query()
    {
        string tmp=p->NodeName();
        if(Query::debug){cout<<tmp<<": before delete1  :"<<p<<"     use:."<<*use<<endl;}
        del();
    }
    
    void Query::del()
    {
        string tmp=p->NodeName();
        if(Query::debug){cout<<tmp<<": before delete2  :"<<p<<"     use:."<<*use<<endl;}
        if(--*use==0)
        {
            delete p;
            delete use;
            if(Query::debug){cout<<tmp<<": delete end"<<endl;}
        }
        else
        {
            if(Query::debug){cout<<tmp<<": delete end(just sub use.)  :"<<p<<"     use:."<<*use<<endl;}
        }
    }
    
    string Query::NodeName()const
    {
        return p->NodeName();
    }
    
    
    Query::Query(const string& _word)
    {
        p=new Leaf(_word);
        use=new unsigned int(1);
        if(Query::debug){cout<<p->NodeName()<<": query 'word' construct "<<p<<"     use:."<<*use<<endl;}
    }
    
    set<line_no> Query::Eval(const TextQuery& _file)const
    {
        return p->Eval(_file);
    }
    
    ostream& Query::display(ostream& os)const
    {
        return p->display(os);
    }
    
    
    
    //end query 定义
    
    Query operator&(const Query& lhs,const Query& rhs)
    {
    //    base_TNode *p=new AndNode(lhs,rhs);
    //    if(Query::debug){cout<<p->NodeName()<<": pointer create "<<p<<endl;}
    //    Query tmp=Query(p);
    //
    //    return tmp;
        return Query(new AndNode(lhs,rhs));//raii 原则,获得资源即初始。
    }
    
    Query operator|(const Query& lhs,const Query& rhs)
    {
    //    base_TNode *p=new OrNode(lhs,rhs);
    //    if(Query::debug){cout<<p->NodeName()<<": pointer create "<<p<<endl;}
    //    Query tmp=Query(p);
    //
    //    return tmp;
        return Query(new OrNode(lhs,rhs));//raii 原则,获得资源即初始。
    }
    
    Query operator~(const Query& lhs)
    {
    //    base_TNode *p=new NotNode(lhs);
    //    if(Query::debug){cout<<p->NodeName()<<": pointer create "<<p<<endl;}
    //    Query tmp=Query(p);
    //
    //    return tmp;
        return Query(new NotNode(lhs));//raii 原则,获得资源即初始。
    }
    
    inline ostream& operator<<(ostream &os, const Query& q)
    {
        return q.display(os);
    }
    
    #endif // TREEQUERY_H_INCLUDED
  • 相关阅读:
    C# UserControl集合属性使用
    类属性的几个特性的含义
    C# 绘图时使用抗锯齿会多出一个像素
    Tooltip导致的无法访问已释放对象
    C#窗口闪烁问题解决
    窗口扩展风格
    动态字段列表实现及List<T>排序
    比较好用的Copy代码到博客VS扩展工具
    Dictionary与SortedDictionary
    VS2017 15.6之后支持直接反编译了
  • 原文地址:https://www.cnblogs.com/lsfv/p/5651502.html
Copyright © 2011-2022 走看看