[CPP] Overloading of operators

1- Operators in OpenCV

Function overloading

If the functions have the same function name, but the input parameters are different, you can define functions for different situations without having to repeatedly define new function names.

  • More convenient to code as follows

Operators for cv::Mat

matexample.cpp

#include <iostream>
#include <opencv2/opencv.hpp>

using namespace std;

int main()
{<!-- -->
    float a[6]={<!-- -->1.0f, 1.0f, 1.0f, 2.0f, 2.0f, 2.0f};
    float b[6]={<!-- -->1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f};
    cv::Mat A(2, 3, CV_32FC1, a);
    cv::Mat B(3, 2, CV_32FC1, b);

    cv::Mat C = A * B;

    cout << "Matrix C = " << endl
        << C << endl;
    return 0;
}

Two operators are overloaded: * and <<

CMakeList.cpp

cmake_minimum_required(VERSION 3.1)
set (CMAKE_CXX_STANDARD 11)

project(mateexample)

find_package(OpenCV REQUIRED)
message(STATUS "OpenCV library status:")
message(STATUS "config: ${OpenCV_DIR}")
message(STATUS " version: ${OpenCV_VERSION}")
message(STATUS " libraries: ${OpenCV_LIBS}")
message(STATUS "include path: ${OpenCV_INCLUDE_DIRS}")

include_directories( ${<!-- -->OpenCV_INCLUDE_DIRS} )

# Declare the executable target built from your sources
add_executable(matexample matexample.cpp)

# Link your application with OpenCV libraries
target_link_libraries(matexample PRIVATE ${<!-- -->OpenCV_LIBS})

brew install openCV
cmake..
make
Matrix C =
[9, 12;
 18, 24]

Operator Overloading

  • Customizes the C++ operators for operands of user-defined types
  • Overloaded operators are functions with special function names

string demo.cpp

#include <iostream>
#include <string>

int main()
{<!-- -->
    std::string s("Hello ");
    s + = "C";
    s.operator + =(" and CPP!");

    std::cout << s << std::endl;
    return 0;
}
Hello C and CPP!

2- Operator Overloading

Operator Overloading

  • Implementation of operator + () and operator + =()

A + B operation: this + t
A + = B operation: this + = t

Example1

time.hpp

#pragma once
#include <iostream>

classMyTime
{<!-- -->
    int hours;
    int minutes;
  public:
    MyTime(): hours(0), minutes(0){<!-- -->}
    MyTime(int h, int m): hours(h), minutes(m){<!-- -->}

    MyTime operator + (const MyTime & t) const
    {<!-- -->
        MyTime sum;
        sum.minutes = this->minutes + t.minutes;
        sum.hours = this->hours + t.hours;

        sum.hours + = sum.minutes / 60;
        sum.minutes %= 60;
        
        return sum;
    }
    MyTime & operator + =(const MyTime & t)
    {<!-- -->
        this->minutes + = t.minutes;
        this->hours + = t.hours;

        this->hours + = this->minutes / 60;
        this->minutes %= 60;
        
        return *this;
    }
    std::string getTime() const
    {<!-- -->
        return std::to_string(this->hours) + " hours and "
                 + std::to_string(this->minutes) + "minutes.";
    }
};

main.cpp

#include <iostream>
#include "time.hpp"

using namespace std;

int main()
{<!-- -->
    MyTime t1(2, 40);
    MyTime t2(1, 20);
    std::cout << (t1 + t2).getTime() << std::endl;

    t1 + = t2; //operator
    t1.operator + =(t2); //function

    std::cout << t1.getTime() << endl;

    return 0;
}


4 hours and 0 minutes.
5 hours and 20 minutes.
  • If one operand is not MyTime, and is an int
MyTime t1(2, 40);
MyTime t2 = t1 + 20;
  • The function can be:
 MyTime operator + (int m) const
    {<!-- -->
        MyTime sum;
        sum.minutes = this->minutes + m;
        sum.hours = this->hours;
        sum.hours + = sum.minutes / 60;
        sum.minutes %= 60;
        return sum;
    }
  • We can even support the following operation to be more user friendly
MyTime t1(2, 40);
MyTime t2 = t1 + "one hour";
 MyTime operator + (const std::string str) const
    {<!-- -->
        MyTime sum = *this;
        if(str=="one hour")
            sum.hours = this->hours + 1;
        else
            std::cerr<< "Only "one hour" is supported." << std::endl;
        return sum;
    }

Example 2

time.hpp

#pragma once
#include 

classMyTime
{
    int hours;
    int minutes;
  public:
    MyTime(): hours(0), minutes(0){}
    MyTime(int h, int m): hours(h), minutes(m){}

    MyTime operator + (const MyTime & t) const
    {
        MyTime sum;
        sum.minutes = this->minutes + t.minutes;
        sum.hours = this->hours + t.hours;

        sum.hours + = sum.minutes / 60;
        sum.minutes %= 60;
        
        return sum;
    }
    MyTime & operator + =(const MyTime & t)
    {
        this->minutes + = t.minutes;
        this->hours + = t.hours;

        this->hours + = this->minutes / 60;
        this->minutes %= 60;
        
        return *this;
    }

    MyTime operator + (int m) const
    {<!-- -->
        MyTime sum;
        sum.minutes = this->minutes + m;
        sum.hours = this->hours;
        sum.hours + = sum.minutes / 60;
        sum.minutes %= 60;
        return sum;
    }
    MyTime & operator + =(int m)
    {
        this->minutes + = m;
        this->hours + = this->minutes / 60;
        this->minutes %= 60;
        return *this;
    }

    MyTime operator + (const std::string str) const
    {<!-- -->
        MyTime sum = *this;
        if(str=="one hour")
            sum.hours = this->hours + 1;
        else
            std::cerr<< "Only "one hour" is supported." << std::endl;
        return sum;
    }
    
    std::string getTime() const
    {
        return std::to_string(this->hours) + " hours and "
                 + std::to_string(this->minutes) + "minutes.";
    }
};

mai.cpp

#include <iostream>
#include "time.hpp"

using namespace std;

int main()
{<!-- -->
    MyTime t1(2, 40);
    std::cout << (t1 + 30).getTime() << std::endl;

    t1 + = 30; //operator
    t1.operator + =(30); //function

    std::cout << t1.getTime() << endl;

    std::cout << (t1 + "one hour").getTime() << std::endl;
    std::cout << (t1 + "two hour").getTime() << std::endl;

    return 0;
}


3 hours and 10 minutes.
3 hours and 40 minutes.
4 hours and 40 minutes.
Only "one hour" is supported.
3 hours and 40 minutes.
  • Overloaded operators are more user-friendly than functions
  • But, wait…
t1 + 20; // operator
t1.operator + (20); // equivalent function invoking
  • How about the expression
20 + t1;

3-friend Functions

friend functions

friend function

  • If we want that operator + can support (int + MyTime)
MyTime t1(2, 40);
20 + t1;
  • Let a friend function to help
  • Friend functions

(1) Declare in a class body
(2) Granted class access to members (including private members)
(3) But not members

  • Again, friend functions are members! They just declared in the class body
class MyTime
{<!-- -->
  public:
    friend MyTime operator + (int m, const MyTime & amp; t)
    {<!-- -->
        return t + m;
    }
};
  • A friend function is defined out of the class
  • No MyTime:: before its function name
class MyTime
{<!-- -->
  public:
    friend MyTime operator + (int m, const MyTime & amp; t);
};
MyTime operator + (int m, const MyTime & t)
{<!-- -->
    return t + m;
}
  • Operator << can also be overloaded
  • but in (cout << t1;) , the first operand is std::ostream, not MyTime
  • To modify the definition of std::ostream ? NO!
  • Use a friend function
 friend std::ostream & amp; operator<<(std::ostream & amp; os, const MyTime & amp; t)
    {<!-- -->
        std::string str = std::to_string(t.hours) + " hours and "
                         + std::to_string(t.minutes) + "minutes.";
        os << str;
        return os;
    }
    friend std::istream & amp; operator>>(std::istream & amp; is, MyTime & amp; t)
    {<!-- -->
        is >> t.hours >> t.minutes;
        t.hours + = t.minutes / 60;
        t.minutes %= 60;
        return is;
    }
  • return The return value must be of std::i/ostream & amp; type, otherwise chain output cannot be performed, such as modifying friend int operator << (...) {...return o }
std::cout << t1 << std::endl; => 0 << std::endl;

Unable to chain calls

Example3

time.hpp

#pragma once
#include 

classMyTime
{
    int hours;
    int minutes;
  public:
    MyTime(): hours(0), minutes(0){}
    MyTime(int h, int m): hours(h), minutes(m){}

    MyTime operator + (const MyTime & t) const
    {
        MyTime sum;
        sum.minutes = this->minutes + t.minutes;
        sum.hours = this->hours + t.hours;

        sum.hours + = sum.minutes / 60;
        sum.minutes %= 60;
        
        return sum;
    }
    MyTime & operator + =(const MyTime & t)
    {
        this->minutes + = t.minutes;
        this->hours + = t.hours;

        this->hours + = this->minutes / 60;
        this->minutes %= 60;
        
        return *this;
    }

    MyTime operator + (int m) const
    {<!-- -->
        MyTime sum;
        sum.minutes = this->minutes + m;
        sum.hours = this->hours;
        sum.hours + = sum.minutes / 60;
        sum.minutes %= 60;
        return sum;
    }

    friend MyTime operator + (int m, const MyTime & amp; t)
    {
        return t + m;
    }

    std::string getTime() const
    {
        return std::to_string(this->hours) + " hours and "
                 + std::to_string(this->minutes) + "minutes.";
    }

    friend std::ostream & amp; operator<<(std::ostream & amp; os, const MyTime & amp; t)
    {<!-- -->
        std::string str = std::to_string(t.hours) + " hours and "
                         + std::to_string(t.minutes) + "minutes.";
        os << str;
        return os;
    }
    friend std::istream & amp; operator>>(std::istream & amp; is, MyTime & amp; t)
    {<!-- -->
        is >> t.hours >> t.minutes;
        t.hours + = t.minutes / 60;
        t.minutes %= 60;
        return is;
    }
};

main.cpp

#include <iostream>
#include "time.hpp"

using namespace std;

int main()
{<!-- -->
    MyTime t1(2, 40);
    std::cout << (30 + t1).getTime() << std::endl;

    std::cout << t1 << std::endl;
    std::cout << "Please input two integers:" << std::endl;
    std::cin >> t1;
    std::cout << t1 << std::endl;

    return 0;
}


3 hours and 10 minutes.
2 hours and 40 minutes.
Please input two integers:
3 80
4 hours and 20 minutes.

4- User Defined Type Conversion

Operator type()

  • Overloaded type conversion: convert the current type to another
 //implicit conversion
    operator int() const
    {<!-- -->
        std::cout << "operator int()" << std::endl;
        return this->hours * 60 + this->minutes;
    }
    //explicit conversion
    explicit operator float() const
    {<!-- -->
        std::cout << "explicit operator float()" << std::endl;
        return float(this->hours * 60 + this->minutes);
    }
MyTime t1(1, 20);
int minutes = t1; //implicit conversion
float f = float(t1); // explicit conversion

Want to convert MyTime into an integer, operator int()
Added explicit: conversion must be explicit, not implicit conversion

  • if:
MyTime t1(1, 20);
int minutes = t1; //implicit conversion
float f = t1; // explicit conversion

This will not report an error, because operator int() is automatically called to convert it to an integer, and then it is forced to convert it to the float type.

Converting Constructor

  • Convert another type to the current
 MyTime(int m): hours(0), minutes(m)
    {<!-- -->
        std::cout << "Constructor MyTime(int)" << std::endl;
        this->hours + = this->minutes / 60;
        this->minutes %= 60;
    }
    MyTime t2 = 70;

Call the constructor directly here

Assignment operator overloading

  • Convert another type to the current
 MyTime & amp; operator=(int m)
    {<!-- -->
        std::cout << "operator=(int)" << std::endl;
        this->hours = 0;
        this->minutes = m;
        this->hours = this->minutes / 60;
        this->minutes %= 60;
        return *this;
    }
    MyTime t3;
    t3 = 80;

Here is the assignment operation

Be careful

  • What is the difference in creating object t2 and t3

The difference between initialization and assignment

Example4

time.hpp

#pragma once
#include <iostream>

classMyTime
{<!-- -->
    int hours;
    int minutes;
  public:
    MyTime(): hours(0), minutes(0)
    {<!-- -->
        std::cout << "Constructor MyTime()" << std::endl;
    }
    MyTime(int m): hours(0), minutes(m)
    {<!-- -->
        std::cout << "Constructor MyTime(int)" << std::endl;
        this->hours + = this->minutes / 60;
        this->minutes %= 60;
    }
    MyTime(int h, int m): hours(h), minutes(m)
    {<!-- -->
        std::cout << "Constructor MyTime(int,int)" << std::endl;
    }
    
    //implicit conversion
    operator int() const
    {<!-- -->
        std::cout << "operator int()" << std::endl;
        return this->hours * 60 + this->minutes;
    }
    //explicit conversion
    explicit operator float() const
    {<!-- -->
        std::cout << "explicit operator float()" << std::endl;
        return float(this->hours * 60 + this->minutes);
    }

    MyTime & operator=(int m)
    {<!-- -->
        std::cout << "operator=(int)" << std::endl;
        this->hours = 0;
        this->minutes = m;
        this->hours = this->minutes / 60;
        this->minutes %= 60;
        return *this;
    }

    friend std::ostream & amp; operator<<(std::ostream & amp; os, const MyTime & amp; t)
    {<!-- -->
        std::string str = std::to_string(t.hours) + " hours and "
                         + std::to_string(t.minutes) + "minutes.";
        os << str;
        return os;
    }
};

main.cpp

#include <iostream>
#include "time.hpp"

using namespace std;

int main()
{<!-- -->
    MyTime t1(1, 20);
    int minutes = t1; //implicit conversion
    float f = float(t1); //explicit conversion.
    std::cout << "minutes = " << minutes << std::endl;
    std::cout << "minutes = " << f << std::endl;

    MyTime t2 = 70;
    std::cout << "t2 is " << t2 << std::endl;

    MyTime t3;
    t3 = 80;
    std::cout << "t3 is " << t3 << std::endl;

    return 0;

}


Constructor MyTime(int,int)
operator int()
explicit operator float()
minutes=80
minutes=80
Constructor MyTime(int)
t2 is 1 hours and 10 minutes.
Constructor MyTime()
operator=(int)
t3 is 1 hour and 20 minutes.

5- Increment and Decrement Operators

Increment and decrement operators

Increment

  • Two operators: prefix increment & postfix increment
 // prefix increment
    MyTime & operator + + ()
    {<!-- -->
        std::cout << "operator prefix increment" << std::endl;
        this->minutes + + ;
        this->hours + = this->minutes / 60;
        this->minutes = this->minutes % 60;
        return *this;
    }
 
    // postfix increment
    MyTime operator + + (int)
    {<!-- -->
        std::cout << "operator postfix increment" << std::endl;
        MyTime old = *this; // keep the old value
        operator + + (); // prefix increment
        return old;
    }

Example5

time.hpp

#pragma once
#include <iostream>

classMyTime
{<!-- -->
    int hours;
    int minutes;
  public:
    MyTime(): hours(0), minutes(0)
    {<!-- -->
        std::cout << "Constructor MyTime()" << std::endl;
    }
    MyTime(int m): hours(0), minutes(m)
    {<!-- -->
        std::cout << "Constructor MyTime(int)" << std::endl;
        this->hours + = this->minutes / 60;
        this->minutes %= 60;
    }
    MyTime(int h, int m): hours(h), minutes(m)
    {<!-- -->
        std::cout << "Constructor MyTime(int,int)" << std::endl;
    }

    // prefix increment
    MyTime & operator + + ()
    {<!-- -->
        this->minutes + + ;
        this->hours + = this->minutes / 60;
        this->minutes = this->minutes % 60;
        return *this;
    }
 
    // postfix increment
    MyTime operator + + (int)
    {<!-- -->
        MyTime old = *this; // keep the old value
        operator + + (); // prefix increment
        return old;
    }

    friend std::ostream & amp; operator<<(std::ostream & amp; os, const MyTime & amp; t)
    {<!-- -->
        std::string str = std::to_string(t.hours) + " hours and "
                         + std::to_string(t.minutes) + "minutes.";
        os << str;
        return os;
    }
};

main.cpp

#include <iostream>
#include "time.hpp"

using namespace std;

int main()
{<!-- -->
    MyTime t1(1, 59);
    MyTime t2 = t1 + + ;
    MyTime t3 = + + t1;

    std::cout << "t1 is " << t1 << std::endl;
    std::cout << "t2 is " << t2 << std::endl;
    std::cout << "t3 is " << t3 << std::endl;

    return 0;

}


Constructor MyTime(int,int)
operator postfix increment
operator prefix increment
operator prefix increment
t1 is 2 hours and 1 minutes.
t2 is 1 hour and 59 minutes.
t3 is 2 hours and 1 minutes.

Operators

  • Operators which can be overloaded