Design pattern (ii) Combined mode composite (expression evaluation)

Source: Internet
Author: User

Combination Mode goal: combining objects into a tree structure to represent a partial overall relationship, composite makes the user consistent with the use of individual objects and composite objects.

Disclosed: This example can be described as a typical application of combinatorial patterns, it is said (the author said) a compiler development team took 2.5 months to implement the expression evaluation, by the author with more than 10 lines of code to achieve this.

Requirements: expression evaluation is an important component of the compiler, in this case you can find the actual code should not be many, because it is I in the "C + + meditation" Inside the example personally knocked out (of course, the author's credit). The purpose is to support a variety of unary operations, the two-dollar operation and even more operations are added to the expression evaluation, the program is easy to expand, easy to use.


Code Show: To tell the truth this example is still not very good to understand, especially for beginners, because it is more abstract, but if you first give him how to use the results, it is easier to see why it is so organized. Each time will forget the author how to achieve, so here concentrated display, convenient later memories.


The first is the main function

From the main function you can see what the author intends to create, what it is at least to accomplish, and then you can guess what you're going to do to get it done.

#include "ExpressNode.h" #include "ValueNode.h" #include "UnaryNode.h" #include "BinaryNode.h" #include "Express.h" void Main () {Express t=express (3); T=express (' + ', t,12);cout<<t<< "=" <<t.eval () <<endl; Express y=express ('-', 4);cout<<y<< "=" <<y.eval () <<endl; Express t1=express (' * ', express ('-', 5), Express (' + ', 3,4));cout<<t1<< "=" <<t1.eval () <<endl; T=express (' * ', t1,t1); Express t2=express (' * ', t,t);cout<<t2<< "=" <<t2.eval () <<endl;}

Operation Result:


See, is the expression evaluation, it seems to be not very convenient, this thing can print your expression, you can also directly find the value of the expression, this natural requirement contains a fact: the expression has a variety of, unary operators, two-dollar operator, a single value is an expression, all types of expressions support the output , both support the calculation results. Of course, you can also add ternary operator expressions.


In this way, at least one expression class is the customer's first contact: Express, the interface of this class, as you might imagine.

Express Class

Express.h

#pragma once#include "ExpressNode.h" #include <iostream>using namespace Std;class express{public:express (int); /valuenode (int) Express (3) Express (Char,const Express),//unarynode (Char,int) Express (' + ', t,12) Express (Char,const Express,const Express);//binarynode (Char,int,int) Express (' + ', 3,4) Express (const express&); express& operator= (const express&); ~express (void); friend ostream& operator<< (ostream& OS, Const express& e) {os<<* (E.P); return OS;} int eval () Const;private:class expressnode* p;//specific functions are implemented by this class, which derives a variety of expressions};

Express.cpp

#include "Express.h" #include "ValueNode.h" #include "UnaryNode.h" #include "BinaryNode.h" express::express (int a) {p= New Valuenode (a);} Express::express (char C, const Express e) {p=new unarynode (c,e);} Express::express (Char C,const Express el,const Express er)//binarynode (char,int,int) {p=new binarynode (c,el,er);} Express::express (const express& E1) {P=e1.p;p->setuse (P->getuse () +1);} express& express::operator= (const express& E1) {(E1.P)->setuse ((E1.P)->getuse () +1);p->setuse (P- >getuse ()-1); if (P->getuse () ==0) delete P;p=e1.p;return *this;} Express::~express (void) {P->setuse (P->getuse ()-1); if (P->getuse () ==0) delete p;} int Express::eval () Const{return p->eval ();}

From the express interface, it can be seen that express created the object to the specific expression class, and the base class pointer to achieve a multi-state, to achieve unified computing, the purpose of unified output expression.


Here is the base class for the various expressions: Expressnode, which is the general form of all expressions, and the interfaces of this class require all expressions to be implemented.


ExpressNode.h

#pragma once#include<iostream>using namespace Std;class expressnode{public:friend class Express;int getUse (void ) const;void setuse (int); friend ostream& operator<< (ostream& os,const expressnode& ExprNode)//(1) The output expression itself {exprnode.print (OS); return OS;} Expressnode (void): Use (1) {}virtual ~expressnode (void);p rotected:virtual void print (ostream& os) const=0;virtual int eval () const=0;//(2) evaluates the value of an expression private:int use;};


ExpressNode.cpp


#include "ExpressNode.h" expressnode::~expressnode (void) {}int expressnode::getuse () Const{return use;} void Expressnode::setuse (int use1) {use=use1;}
This class seems to have done nothing, just provide a consistent interface for subclasses to implement, the only one shaping variable to hold the reference count, so that the expression does not copy a large number of copies


The following are the implementations of the various expression classes: Numeric Expression Valuenode (for numeric constants), unary expression unarynode (positive, negative), two-tuple expression binarynode (two-expression-op +-*/Add, subtract, multiply, divide)

ValueNode.h

#pragma once#include "ExpressNode.h" #include "Express.h" class Valuenode:p ublic expressnode{public:friend class Express; Valuenode (void); Valuenode (int value1); ~valuenode (void);p rivate:void print (ostream& os) const;int eval () const {return value;} int value;};

Evaluating a numeric expression is the value that you save


ValueNode.cpp

#include "ValueNode.h" valuenode::valuenode (void) {}valuenode::valuenode (int value1): value (value1) {}valuenode::~ Valuenode (void) {}void valuenode::p rint (std::ostream& os) const{os<<value;}
outputting A numeric expression is the output of its own saved value

UnaryNode.h

#pragma once#include "Express.h" #include "ExpressNode.h" class Unarynode:p ublic expressnode{public:friend class Express; Unarynode (void); Unarynode (char c,class Express left1) ~unarynode (void);p rivate:void print (ostream& os) const;int eval () const; char Opend;class Express left;};
As can be seen from here, the basis of the positive and negative operations is a general expression, any complex expression can be plus positive and negative operations.

UnaryNode.cpp

#include "Express.h" #include "UnaryNode.h" Unarynode::unarynode (char c,class Express left1): Opend (c), left (LEFT1) {} Unarynode::~unarynode (void) {}void unarynode::p rint (std::ostream &os) const{os<< "(<<opend<< left<< ")";} int Unarynode::eval () const{if (opend== '-') return ( -1) *left.eval (); throw "error, bad op int unarynode";}


BinaryNode.h

#pragma once#include "ExpressNode.h" #include "Express.h" class Binarynode:p ublic expressnode{public:friend class Express; Binarynode (void); Binarynode (Char,class express,class Express) ~binarynode (void);p rivate:void print (ostream&) const;int eval () Const;char Opend;class Express Left;class Express right;};
As can be seen from here, the two-dollar expression is an operator, two general expression, the specific work or down assignment, only do the operator to do. The output is also delegated down.

BinaryNode.cpp

#include "BinaryNode.h" Binarynode::binarynode (char C,class Express Left1,class Express right1): Opend (c), left (LEFT1), Right (right1) {}binarynode::~binarynode (void) {}void binarynode::p rint (ostream& os) const{os<< "(<< left<<opend<<right<< ")";} int Binarynode::eval () const{int op1=left.eval (), int op2=right.eval (), if (opend== ' + ') return op1+op2;if (opend== '-') Return op1-op2;if (opend== ' * ') return op1*op2;if (opend== '/' && op2!=0) return Op1/op2;throw "error, bad operation In  Binarynode ";}

Ultimately, all of the evaluation operations fall on the head of a numeric expression, and the output is a process of outputting a final summary from the bottom of the tree.


This example can be described as a typical application of combinatorial patterns, it is said (the author said) a compiler development team took 2.5 months to implement the expression evaluation, by the author with more than 10 lines of code to achieve this.














Design pattern (ii) Combined mode composite (expression evaluation)

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.