#include #include #include #include #include class Variable_Base { public: virtual ~Variable_Base() = default; virtual void print(std::ostream& os) const = 0; virtual Variable_Base* add(Variable_Base*) const { throw std::invalid_argument { "Unknown operator" }; } }; class Number : public Variable_Base { public: Number(double value) : value { value } { } void print(std::ostream& os) const override; Variable_Base* add(Variable_Base* rhs) const override; private: double value; }; class String : public Variable_Base { public: String(std::string const& value) : value { value } { } void print(std::ostream& os) const override; Variable_Base* add(Variable_Base* rhs) const override; private: std::string value; }; void Number::print(std::ostream& os) const { os << value; } Variable_Base* Number::add(Variable_Base* rhs) const { if (auto p = dynamic_cast(rhs)) { return new Number{value + p->value}; } return Variable_Base::add(rhs); } void String::print(std::ostream& os) const { os << value; } Variable_Base* String::add(Variable_Base* rhs) const { if (dynamic_cast(rhs)) { std::ostringstream oss; print(oss); rhs->print(oss); return new String{oss.str()}; } else if (auto p = dynamic_cast(rhs)) { return new String{ value + p->value }; } return Variable_Base::add(rhs); } class Variable { public: Variable(double number) : data { new Number { number } } { } Variable(std::string const& value) : data { new String { value } } { } ~Variable() { delete data; } Variable operator+(Variable const& rhs) const { return Variable { data->add(rhs.data) }; } Variable& operator=(double number) { delete data; data = new Number{number}; return *this; } Variable& operator=(std::string const& value) { delete data; data = new String{value}; return *this; } private: friend std::ostream& operator<<(std::ostream& os, Variable const& rhs) { rhs.data->print(os); return os; } Variable(Variable_Base* data) : data { data } { } Variable_Base* data; }; int main() { Variable var1 { "hello" }; Variable var2 { 5.3 }; Variable var3 { "world" }; Variable var4 { 1.2 }; std::cout << var1 + var2 << std::endl; std::cout << var1 + var3 << std::endl; try { std::cout << var2 + var3 << std::endl; } catch (std::exception& e) { std::cerr << e.what() << std::endl; } std::cout << var2 + var4 << std::endl; }