/*
* This example code shows how to use a class hierarchy to implement a
* simple calculator. For simplicity, we've put all the code in one file.
*
* The design is as follows:
* We have an abstract class called Expression, which has two subclasses:
* Number and BinaryExpression. Number is a simple number, and BinaryExpression
* is an expression that has two subexpressions and an operator.
*/
#include <iostream>
#include <string>
#include <type_traits>
// Abstract base class
class Expression {
public:
virtual ~Expression() = default;
virtual double evaluate() const = 0;
};
// Derived class #1: Number
class Number : public Expression {
public:
explicit Number(double value);
~Number() override = default;
double evaluate() const override;
private:
double value_;
};
Number::Number(double value) : value_{value} {
// Nothing (else) to do
}
double Number::evaluate() const {
return value_;
}
// Derived class #2: BinaryExpression
enum Operator { PLUS, MINUS, TIMES, DIVIDE };
class BinaryExpression : public Expression {
public:
BinaryExpression(Operator op, Expression* left, Expression* right);
~BinaryExpression() override;
double evaluate() const override;
// disallow copying and assignment
BinaryExpression(const BinaryExpression&) = delete;
BinaryExpression& operator=(const BinaryExpression&) = delete;
private:
Operator op_;
Expression* left_;
Expression* right_;
};
BinaryExpression::BinaryExpression(Operator op, Expression* left,
Expression* right)
: op_{op}, left_{left}, right_{right} {
// Nothing (else) to do
}
BinaryExpression::~BinaryExpression() {
delete left_;
delete right_;
}
double BinaryExpression::evaluate() const {
double leftValue = left_->evaluate();
double rightValue = right_->evaluate();
switch (op_) {
case PLUS:
return leftValue + rightValue;
case MINUS:
return leftValue - rightValue;
case TIMES:
return leftValue * rightValue;
case DIVIDE:
return leftValue / rightValue;
default:
// should never get here
return 0;
}
}
int main() {
Expression* expr = new BinaryExpression(
PLUS, new Number(2),
new BinaryExpression(TIMES, new Number(8), new Number(5)));
// ^-- this is the expression 2 + (8 * 5) represented as an Expression
std::cout << expr->evaluate() << std::endl;
delete expr;
// ^-- this destroys and deallocates the entire expression tree
// note that we didn't have to make expr a pointer to an object
// on the heap, but since every other expression is a pointer
// it's more consistent to do so
}