📖
Go C++
  • Introduction
  • Chapter 1: What You Must Know First
    • Virtual Address Space of Process: Memory Partition and Layout
    • Function Call: Stack Frame
    • Program Compiling and Linking
  • Chapter 2: C++ Basics Improvement
    • Default Parameters
    • Inline Function
    • Function Overloading
    • new and delete
    • const and Pointers
    • References in Detail
  • Chapter 3: Object-Oriented Principles
  • Class and Object
  • Constructor and Destructor
  • Shallow Copy and Deep Copy
  • Initializer List
  • Various Member Functions
  • Pointer to Class Members
  • Chapter 4: Template Programming
  • Function Templates
  • Class Templates
  • Memory Allocators
  • Chapter 5: Operator Overloading
    • Operator Overloading
    • Introduction to Iterators
    • Issues of Iterator Invalidation
    • More about new and delete
    • Overloading of new and delete: Object Pool
  • Chapter 6: Inheritance and Polymorphism
    • Look inside Inheritance
    • More about Inheritance
    • Virtual Functions, Static Binding and Dynamic Binding
    • More about Virtual Functions
    • Understanding Polymorphism
    • Abstract Classes
    • Frequently Asked Interview Questions: Polymorphism
  • Chapter 7: Multiple Inheritance
    • Virtual Inheritance and Virtual Base Classes
    • Diamond Problem
    • Four Kinds of Type Conversions
  • Chapter 8: Standard Template Library
    • Sequence Containers
    • Container Adaptors
    • Associative Containers
    • More about Iterators
    • Function Objects
    • Generic Algorithms, Binders and Lambda Expressions
  • Chapter 9: Object Optimization
    • Behind the Object
    • Optimizing Objects in Functions
    • Member Functions with Rvalue References
    • Move Semantics and Perfect Forwarding
  • Chapter 10: Smart Pointers
    • Smart Pointers
    • Smart Pointers without Reference Counting
    • Smart Pointers with Reference Counting
    • Custom Deleters
  • Chapter 11: Function Objects and Binders
    • More about Binders
    • Introduction to std::function
    • Template Specialization and Argument Deduction
    • More about std::function
    • std::bind(): A Simple Thread Pool
    • More about Lambda Expressions
  • Chapter 12: Multithreading
    • Important Features in C++11
    • Multithreaded Programming with std::thread
    • Mutual Exclusion
    • Producer-Consumer Problem
    • Atomic Operations
    • Thread Visibility and volatile
  • Chapter 13: Design Patterns
    • Singleton Pattern
    • Factory Pattern
    • Proxy Pattern
    • Decorator Pattern
    • Adapter Pattern
    • Observer Pattern
Powered by GitBook
On this page

Was this helpful?

  1. Chapter 5: Operator Overloading

Operator Overloading

Operator overloading is one of the most fancy feature in C++. It is is a specific case of polymorphism, where different operators can be overloaded so that object operations are the same as the built-in types of the compiler, which greatly facilitate programmers.

Here we defined a class MyComplex which represents a complex number. The complex number has a real part mreal and an image part mimage.

class MyComplex {
 public:
  MyComplex(int r = 0, int i = 0) : mreal(r), mimage(i) {}
​
 private:
  int mreal;
  int mimage;
};
​
int main() {
  MyComplex c1(10, 10);
  MyComplex c2(20, 20);
  MyComplex c3 = c1 + c2;  // c1.operator+(c2)
  return 0;
}

Now in the main function we would like to add two MyComplex objects. For object types, a + b is just a.operator+(b), so we need to overload operator +, which simply add the real part and image part of two complex numbers separately.

MyComplex MyComplex::operator+(const MyComplex &other) {
    return MyComplex(this->mreal + other.mreal, this->mimage + other.mimage);
  }

It is also valid to add MyComplex with a number. In the following case, number 20 is converted into a temporary object c(20, 0) when passed inside.

int main() {
  MyComplex c1(10, 10);
  MyComplex c2 = c1 + 20;   // c1.operator+(20)
  return 0;
}

But it won't work if the constant is before the operator +. Since 20 is a constant, there's not any evidence for the compiler to call the overloaded function of MyComplex. In this case, the compiler will call the global operator +, so we also need to overload it.

int main() {
  MyComplex c1(10, 10);
  MyComplex c2 = 20 + c1;   // ::operator+(20, c1)
  return 0;
}

The global operator takes the object before it and after it as parameters. When the compiler does object operations, it will first call the overloaded function of the member method. If it is not found, the compiler will go on finding the appropriate overloaded function in the global scope.

MyComplex operator+(const MyComplex &c1, const MyComplex &c2) {
  return MyComplex(c1.mreal + c2.mreal, c1.mimage + c2.mimage);
}

Here inside this function we use the private member variables of MyComplex, which is apparently not allowed. To fix this, we can use keyword friend inside MyComplex, to give the function access to private members.

class MyComplex {
    ...
private:
  int mreal;
  int mimage;
  friend MyComplex operator+(const MyComplex &c1, const MyComplex &c2);
}

Now our global overloaded function can also handle the sum of two MyComplex objects, so the overloaded member function is no longer needed.

Now let's deal with the self growth operator ++. There are two types of them, one is before the object and the other is after the object. The former adds one to the object, and returns its value, while the latter returns the original value, and then adds one.

int main() {
  MyComplex c1(10, 10);
  MyComplex c2 = c1++;  // c1.operator++(int)
  MyComplex c3 = ++c1;  // c1.operator++()
  return 0;
}

The one before the object is represented as a.operator++(), and the one after the object is represented as a.operator++(int). The int parameter is not used. It is solely for the compiler to distinguish them.

MyComplex MyComplex::operator++(int) {
    return MyComplex(mreal++, mimage++);
}
​
MyComplex &MyComplex::operator++() {
    mreal += 1;
    mimage += 1;
    return *this;
}

We can also overload operator +=, which is simple in this case:

void MyComplex::operator+=(const MyComplex &other) {
    mreal += other.mreal;
    mimage += other.mimage;
}

We can also overload the output stream operator <<. It is also a global function, which takes the ostream object as the first parameter, and our MyComplex object as the second. Similarly, it should also be defined as friend inside MyComplex.

std::ostream &operator<<(std::ostream &out, const MyComplex &c) {
  return out << c.mreal << "+" << c.mimage << "i";
}

Now we can use output stream to print our self-defined complex class.

int main() {
  MyComplex c1(10, 10);
  MyComplex c2(20, 20);
  std::cout << c1 << " " << c2 << std::endl;    // 10+10i 20+20i
  return 0;
}

The input stream is similar:

std::istream &operator>>(std::istream &in, MyComplex &c) {
  return in >> c.mreal >> c.mimage;
}
PreviousMemory AllocatorsNextIntroduction to Iterators

Last updated 5 years ago

Was this helpful?