After a bit of investigation I was able to write code that using dynamic binding it nicely surrounds with parenthesis the operands of a given expression.
Now it's easy test the expressions of the exercise and answer to it.
Code:
#include <iostream>
#include <memory>
using namespace std;
class Backend
{
friend class Frontend;
protected:
~Backend() = default;
private:
virtual string get_expr() const = 0;
};
class Frontend
{
friend Frontend operator~(const Frontend&);
friend Frontend operator|(const Frontend&, const Frontend&);
friend Frontend operator&(const Frontend&, const Frontend&);
public:
Frontend(const string&);
string get_expr() const {return f ->get_expr(); }
private:
Frontend(shared_ptr<Backend> b): f(b) { }
shared_ptr<Backend> f;
};
class Operand: public Backend
{
friend class Frontend;
protected:
Operand(const string& s): word(s) { }
string get_expr() const {return word;}
private:
string word;
};
inline Frontend::Frontend(const string& s): f(new Operand(s)) { }
class NotExpr: public Backend
{
friend Frontend operator~(const Frontend&);
protected:
NotExpr(const Frontend& f): front(f) { }
string get_expr() const {return "~(" + front.get_expr() + ")"; }
private:
Frontend front;
};
class OrExpr: public Backend
{
friend Frontend operator|(const Frontend&, const Frontend&);
protected:
OrExpr(const Frontend& l, const Frontend& r, string s): lOp(l), rOp(r), symbol(s) { }
string get_expr() const {return "(" + lOp.get_expr() + " " + symbol + " " + rOp.get_expr() + ")"; }
private:
Frontend lOp, rOp;
string symbol;
};
class AndExpr: public Backend
{
friend Frontend operator&(const Frontend&, const Frontend&);
protected:
AndExpr(const Frontend& l, const Frontend& r, string s): lOp(l), rOp(r), symbol(s) { }
string get_expr() const {return "(" + lOp.get_expr() + " " + symbol + " " + rOp.get_expr() + ")"; }
private:
Frontend lOp, rOp;
string symbol;
};
Frontend operator~(const Frontend& f)
{
return shared_ptr<Backend>(new NotExpr(f));
}
Frontend operator|(const Frontend& l, const Frontend& r)
{
return shared_ptr<Backend>(new OrExpr(l, r, "|"));
}
Frontend operator&(const Frontend& l, const Frontend& r)
{
return shared_ptr<Backend>(new AndExpr(l, r, "&"));
}
ostream& operator<<(ostream& os, const Frontend& f)
{
os << f.get_expr() << flush;
return os;
}
int main()
{
using Query = Frontend;
Query q=Query("s1") | Query("s2") & ~ Query("s3");
cout << q << endl; // prints: (s1 | (s2 & ~(s3)))
q=Query("s1") | (Query("s2") & ~ Query("s3"));
cout << q << endl; // prints: (s1 | (s2 & ~(s3)))
q=(Query("s1") & (Query("s2")) | (Query("s3") & Query("s4")));
cout << q << endl; // prints: ((s1 & s2) | (s3 & s4))
return EXIT_SUCCESS;
}
The correct answers are:
Code:
/* Exercise 15.31: Given that s1, s2, s3, and s4 are all strings, determine
* what objects are created in the following expressions:
*
* (a) Query(s1) | Query(s2) & ~ Query(s3);
* (b) Query(s1) | (Query(s2) & ~ Query(s3));
* (c) (Query(s1) & (Query(s2)) | (Query(s3) & Query(s4)));
*
* a) OrQuery --- AndQuery --- NotQuery --- WordQuery(s3)
* | |
* | --- WordQuery(s2)
* |
* --- WordQuery(s1)
*
* b) The same of a)
*
* c) OrQuery --- AndQuery --- WordQuery(s4)
* | |
* | --- WordQuery(s3)
* |
* --- AndQuery --- WordQuery(s2)
* |
* --- WordQuery(s1)
*/
HTH