#include <iostream>

class Expr {
public:
    virtual void print(std::ostream&) = 0;
    virtual ~Expr() { }
};

class IntExpr: public Expr {
public:
    IntExpr(int n0): n(n0) { }
    void print(ostream& s) {
	s << n;
    };

private:
    int n;
};

class UnaryExpr: public Expr {
public:
    UnaryExpr(const char* s, Expr* e0):
	op(s), e(e0) { }
    void print(ostream& s) {
	s << "(" << op;
	e->print(s);
	s << ")";
    }
    ~UnaryExpr() { delete e; }

private:
    Expr* e;
    const char* op;
};

class BinaryExpr: public Expr {
public:
    BinaryExpr(const char* s, Expr* e01, Expr* e02):
	op(s), e1(e01), e2(e02) { }
    void print(ostream& s) {
	s << "(";
	e1->print(s);
	s << op;
	e2->print(s);
	s << ")";
    }
    ~BinaryExpr() {
	delete e1;
	delete e2;
    }
private:
    const char* op;
    Expr* e1;
    Expr* e2;
};

int main()
{
    Expr* three = new IntExpr(3);
    Expr* four = new IntExpr(4);
    Expr* five = new IntExpr(5);
    Expr* negfive = new UnaryExpr("-", five);
    Expr* twelve = new BinaryExpr("*", three, four);
    Expr* seven = new BinaryExpr("+", negfive, twelve);

    seven->print(cout);
}

