Operator Overloading
0. Overview
We have some clue of package < iostream> now. However, for now, we could only do the operator based on default data type, such as int, char. What if we want to do operator on the user-defined class? We need to do operator overloading.
This time, we will overloading the operator+, operator*, operator++, operator[], operator<<, operator>>.
1. User-defined Class
Before overloading, let’s define a class for those operator.
// console cin, cout
#include<iostream>
// file in, out
#include<fstream>
using namespace std;
class ThreeD{
public:
int ht;
int wid;
int dep;
// default constructor
ThreeD() {
ht = wid = dep = 0;
}
// know knid of constructor
ThreeD(int i, int j, int k): ht(i), wid(j), dep(k) {}
int getVol(){ return ht * wid * dep; }
// overload operator
ThreeD operator+(ThreeD t);
ThreeD operator*(ThreeD t);
ThreeD operator++(); // prefix
ThreeD operator++(int neverUsed); // postfix
int & operator[](int k);
//friend: allow function to access private paramenter
friend ostream& operator<<(ostream& str, const ThreeD t);
friend istream& operator>>(istream& str, ThreeD& t);
};
2. Operator+, Operator*
ThreeD ThreeD::operator+(ThreeD t){
ThreeD temp;
temp.ht = ht;
temp.wid = t.wid;
temp.dep = dep + t.dep;
return temp;
}
ThreeD ThreeD::operator*(ThreeD t){
ThreeD temp;
temp.ht = ht * t.ht;
temp.wid = wid * t.wid;
temp.dep = dep * t.dep;
return temp;
}
2. Operator++: prefix and postfix
For operator++, we have two types of that: prefix operator++ and postfix operator++. The way complier to distinguish these two operator++ is whether the function take the parameter.
// prefix
// complier knows that the operator without argument is prefix
ThreeD ThreeD::operator++(){
++ht;
++wid;
++dep;
// this is a pointer pointing to the current object
return *this;
}
// postfix
// complier knows that the operator with argument is postfix
// store the value first,which will be return at the end
// then, apply the increment.
ThreeD ThreeD::operator++(int neverUsed){
ThreeD tmp = *this;
ht++;
wid++;
dep++;
return tmp;
}
3. Operator[]: return by reference
Similar to array, operator[] is to return the result by index/reference.
// if defined in this way, it's read-only
// const int & ThreeD::operator[](int k)
//The origianl object will be returned to the calling function.
//No extra copying effort is needed. It is faster than return by value,
//which requires an extra copy to be created and returned to the calling function.
//Because an object is returned, rather than a value, the function can appear
//on the left side of an statement.
int & ThreeD::operator[](int k){
switch(k){
case 0:
// ht will be directly used in calling function
return ht;
case 1:
return wid;
case 2:
return dep;
default:
return ht;
}
}
4. ostream: operator<<, istream: operator>>
These two functions is used to handle the output a class or input a class by cout, cint.
ostream& operator<<(ostream& str, const ThreeD t) {
str << "[" << t.ht << ", " << t.wid << ", " << t.dep << "]";
return str;
}
istream& operator>>(istream& str, ThreeD& t) {
str >> t.ht >> t.wid >> t.dep;
return str;
}
4. ofstream: operator<<, ifstream: operator>>
These two functions is used to handle the output a class or input a class by file.
ofstream& operator<<(ofstream& str, const ThreeD& t) {
str << t.ht << " " << t.wid << " " << t.dep;
return str;
}
ifstream& operator>>(ifstream& str, ThreeD& t) {
str >> t.ht >> t.wid >> t.dep;
return str;
}
5. Complete Code
The complete code is here:
// Operator Overloading
// console cin, cout
#include<iostream>
// file in, out
#include<fstream>
using namespace std;
class ThreeD{
public:
int ht;
int wid;
int dep;
// default constructor
ThreeD() {
ht = wid = dep = 0;
}
// know knid of constructor
ThreeD(int i, int j, int k): ht(i), wid(j), dep(k) {}
int getVol(){ return ht * wid * dep; }
// overload operator
ThreeD operator+(ThreeD t);
ThreeD operator*(ThreeD t);
ThreeD operator++(); // prefix
ThreeD operator++(int neverUsed); // postfix
int & operator[](int k);
//friend: allow function to access private paramenter
friend ostream& operator<<(ostream& str, const ThreeD t);
friend istream& operator>>(istream& str, ThreeD& t);
};
ThreeD ThreeD::operator+(ThreeD t){
ThreeD temp;
temp.ht = ht;
temp.wid = t.wid;
temp.dep = dep + t.dep;
return temp;
}
ThreeD ThreeD::operator*(ThreeD t){
ThreeD temp;
temp.ht = ht * t.ht;
temp.wid = wid * t.wid;
temp.dep = dep * t.dep;
return temp;
}
// prefix
// complier knows that the operator without argument is prefix
ThreeD ThreeD::operator++(){
++ht;
++wid;
++dep;
// this is a pointer pointing to the current object
return *this;
}
// postfix
// complier knows that the operator with argument is postfix
// store the value first,which will be return at the end
// then, apply the increment.
ThreeD ThreeD::operator++(int neverUsed){
ThreeD tmp = *this;
ht++;
wid++;
dep++;
return tmp;
}
// return by ref
// if defined in this way, it's read-only
// const int & ThreeD::operator[](int k)
//The origianl object will be returned to the calling function.
//No extra copying effort is needed. It is faster than return by value,
//which requires an extra copy to be created and returned to the calling function.
//Because an object is returned, rather than a value, the function can appear
//on the left side of an statement.
int & ThreeD::operator[](int k){
switch(k){
case 0:
// ht will be directly used in calling function
return ht;
case 1:
return wid;
case 2:
return dep;
default:
return ht;
}
}
ostream& operator<<(ostream& str, const ThreeD t) {
str << "[" << t.ht << ", " << t.wid << ", " << t.dep << "]";
return str;
}
istream& operator>>(istream& str, ThreeD& t) {
str >> t.ht >> t.wid >> t.dep;
return str;
}
ofstream& operator<<(ofstream& str, const ThreeD& t) {
str << t.ht << " " << t.wid << " " << t.dep;
return str;
}
ifstream& operator>>(ifstream& str, ThreeD& t) {
str >> t.ht >> t.wid >> t.dep;
return str;
}
int main(){
ThreeD t1(3,4,5), t2(10, 11, 12), t3, t4, t5, t6;
int i1{ 10 };
int i2{ 20 }, i3;
i3 = i1 + i2;
// complier will convert it into:
// t3 = t1.operator+(t2);
t3 = t1 + t2;
// it's same as t4 = t1.operator*(t2);
t4 = t1 * t2;
// prefix
t5 = ++t2;
//postfix
t6 = t2++;
t1[2] = 100;
cout << t1[2] << endl;
cout << t1 << endl;
cin >> t4;
cout << t4 << endl;
ofstream out("data1.txt");
out << t1 << endl;
//opearating system level
out.close();
ifstream in("data1.txt");
in >> t1;
cout << t1 << endl;
in.close();
return 0;
}