Operator overloading in C++
Operator overloading in C++ allows us to write natural expressions like d = a + b / c; with our own classes.
The above expression could be equal to d = a.add(b.divide(c)); which results in hard to read code.
Operator overloading by Example
This example will add basic arithmetic operations: addition, subtraction, multiplication and division to Complex number class. These operations will use operators: +, -, *, / and their assigning counterparts +=, -=, *=, /=. Only addition will be implemented.
We will also add input/output operators to read/write from/to standard input/output. Both operators are free functions (and not class methods). Input operator operator<< takes two arguments: a reference to an input stream and a constant reference to object to write, and returns a reference to the input stream. Output operator operator>> takes two arguments: a reference to an output stream and a reference to object to write, it returns as well a reference to the output stream.
#include <iostream> #include <sstream> template <typename T = double> class Complex { public: typedef T value_type; Complex() : m_real(T()) , m_imag(T()) {} Complex(T const& real, T const& imag) : m_real(real) , m_imag(imag) {} T& real() { return m_real; } T const& real() const { return m_real; } T& imag() { return m_imag; } T const& imag() const { return m_imag; } /// constructor Complex(Complex<T> const& other) = default; /// destructor virtual ~Complex() = default; // assignment operator, generated by compiler Complex<T>& operator=(Complex<T> const& other) = default; // addition Complex<T> operator+(Complex<T> const& rhs) const; // this could be a template method with any Complex<S> convertible to Complex<T> Complex<T>& operator+=(Complex<T> const& rhs); // subtraction Complex<T> operator-(Complex<T> const& rhs) const; Complex<T>& operator-=(Complex<T> const& rhs); // multiplication Complex<T> operator*(Complex<T> const& rhs) const; Complex<T>& operator*=(Complex<T> const& rhs); // division Complex<T> operator/(Complex<T> const& rhs) const; Complex<T>& operator/=(Complex<T> const& rhs); private: value_type m_real; value_type m_imag; }; template <typename T> Complex<T> Complex<T>::operator+(Complex<T> const& rhs) const { Complex<T> result = *this; result += rhs; return result; } template <typename T> Complex<T>& Complex<T>::operator+=(Complex<T> const& rhs) { m_real += rhs.m_real; m_imag += rhs.m_imag; return *this; } template <typename T> std::ostream& operator<<(std::ostream& os, Complex<T> const& obj) { // output (real_part + imaginary_part"i") os << "(" << obj.real() << " + " << obj.imag() << "i)"; return os; } template <typename T> std::istream& operator>>(std::istream& is, Complex<T>& obj) { // does not check std::istream::fail() typedef char CharT; CharT c; is >> std::ws; // skip whitespaces is >> c; // should start with opening parenthesis '(' if (c != '(') { is.setstate(std::ios_base::failbit); return is; } is >> std::ws; // skip whitespaces is >> obj.real(); // read real part is >> std::ws; // skip whitespaces is >> c; // should get '+' (imaginary part will follow) or ')' (end) if (c == ')') { return is; } else if (c != '+') { is.setstate(std::ios_base::failbit); return is; } // got '+', get imaginary part is >> std::ws; // skip whitespaces is >> obj.imag(); // should get 'i' is >> std::ws; // skip whitespaces is >> c; if (c != 'i') { is.setstate(std::ios_base::failbit); return is; } // should get closing parenthesis ')' is >> std::ws; // skip whitespaces is >> c; if (c != ')') { is.setstate(std::ios_base::failbit); return is; } return is; } int main() { Complex<> c1(1.0, 2.0); Complex<> c2(3.3, -1.5); Complex<> cpls = c1 + c2; //Complex<> cmin = c1 - c2; //Complex<> cmlt = c1 * c2; //Complex<> cdiv = c1 / c2; std::cout << c1 << " + " << c2 << " == " << cpls << "\n"; Complex<> c3; std::stringstream ssin; ssin << "(3.5 + 2.9 i)"; ssin >> c3; std::cout << c3 << "\n"; return 0; }
Output:
(1 + 2i) + (3.3 + -1.5i) == (4.3 + 0.5i) (3.5 + 2.9i)
Functors in C++
Functors are classes with overloaded parenthesis operator operator() which can have any number of arguments.
This section is incomplete |