C++ operator overloading

The essence of overloading is function overloading. It can give multiple meanings to operators, so that operators have different types of behaviors when acting on different types of data.

The specific format of operator overloading:

Return value type operator operator (formal parameter list)

{

}

Operator overloading as a normal function

When operators are overloaded, they can be overloaded as ordinary member functions and class member functions. This section explains ordinary member functions.

Here you need to pay attention to the following points when compiling the program:

The compiler will convert places with operators into calls to operator functions;

Put the operand of the operator -> the parameter of the operation function;

When overloaded multiple times, the specific operator function will be called based on the actual parameter type.

Take the addition and subtraction operators as an example

#include<iostream>
using namespace std;
class complex{//A complex number class, with real numbers and imaginary numbers

public:
double real;
double imaginary;
complex(double i=0.0,double j=0.0)//Constructor
{
real=i;
imaginary=j;
}
friend complex operator + (const complex & amp;a,const complex & amp;b);//A friend function of the complex number class, an overloaded function of the plus operator
};
 complex operator + (const complex & amp;a,const complex & amp;b)//Define the addition operator, add the real numbers of the two numbers, and add the imaginary numbers
{
return complex(a.real + b.real,a.imaginary + b.imaginary);//"Class name (parameter list)" represents an object
}
int main()
{
complex a(1,2),b(3,4),c;
c=a + b;
cout<<c.real<<" "<<c.imaginary <<endl;
return 0;
}

The running result is

4 6

From this code, it is not difficult to see the meaning of operator overloading. For a complex number class with real numbers and imaginary numbers, the default operator does not allow us to directly add two objects. After overloading, we can use simple object addition Add the value.

Overloaded as a member function of the class

The difference between overloaded member functions of a class and ordinary members is that they need to be declared within the class, and the definition can be within the class or outside the class.

Let us feel the difference through a piece of code

#include<iostream>
using namespace std
class complex{
public:
double real;
double imaginary;
complex(double r=0.0,double m=0.0):real(r),imaginary(m){}//Definition of constructor
complex operator + (const complex & amp;);//In-class declaration of addition operator
complex operator-(const complex & amp;);
\t\t\t
};
complex complex::operator + (const complex & amp;operand2){//Extra-class definition of addition operator
return complex(real + operand2.real,imaginary + operand2.imaginary );
}
complex complex::operator-(const complex & amp; operand2){//We don’t want the original parameters to be changed, so using const types and reference names as formal parameters can reduce the memory occupied by the code.
return complex(real-operand2.real,imaginary-operand2.imaginary);
}
int main()
{
complex x,y(4.3,8.2),z(3.3,1.1);
x=y + z;
x=y-z;
cout<<x.real<<" "<<x.imaginary<<endl;
return 0;
}

The running result is

1 7.1

In addition to the difference between declarations inside and outside the class, there is another point we can notice: the number of formal parameters of ordinary member functions and class member functions are not the same. Why is this? Because there is a hidden member function in the class. The this pointer points to the object on the left side of the assignment operator, so we can draw the conclusion:

Operators are overloaded as ordinary member functions, the number of formal parameters = the number of operators

Overloaded as a member function of the class, the number of formal parameters = the number of operators – 1

Overloading of assignment operator

After the assignment operator is overloaded, even if the data types on both sides of the equal sign are different, it can be overloaded normally. What happens after the assignment depends on the content of the overloaded function body. One thing to note:

Assignment operators can only be overloaded as member functions

Let us understand further through a piece of code

#include<iostream>
using namespace std;
class String{
private:
char *str;
public:
String():str(NULL){}//Constructor
const char*c_str(){return str;}
char *operator=(const char*s);//Declaration of assignment operator overloading
~String();//Destructor
};
char * String::operator=(const char*s){//Member function of character pointer type, the return value is an address or pointer
if(str) delete[]str;//If there are elements in the assigned object, delete the elements to facilitate subsequent assignments
if(s){
str=new char[strlen(s) + 1];//If the assignment is not empty, open up a space 1 more than the length of the string for str to store the string and '/0'
strcpy(str,s);
}
else
str=NULL;//The assignment is empty, then str is returned empty.
return str;
}
String::~String() {
if(str) delete[]str;
};
int main(){
String s;
s="Good Luck,";
cout<<s.c_str()<<endl;
s="Shenzhou 8!";
cout<<s.c_str()<<endl;
return 0;
}

operation result

Good Luck,
Shenzhou 8!

Here we introduce the concepts of deep copy and shallow copy.

Now there are two objects of string type s1, s2

Sting s2=”this”;

s1=s2;

What will happen if you only perform simple assignment? The output of s1 is normal, but the bottom layer becomes like this.

The two objects point to the same address. If the member variables of one object are changed, the other object will also change accordingly. This is not what we want.

Therefore, an overloading of the assignment operator is required to implement deep copying, so that the content within the address can be assigned:

In addition, when writing the assignment operator overloaded function body, it is recommended not to define it as a non-return value type. The return value is preferably *this, so that errors are less likely to occur during continuous assignments.

Overloading of stream insertion operator and stream extraction operator

When learning C++, some people may be curious about what cin>> and cout<< are. In fact, there is nothing strange about <<, >>. They are just left shift and right shift operations in bit operators. symbol. The reason why cin>> and cout<< can enter input and output is precisely because they are overloaded. cout is defined in iostream, an object of the ostream class, and cin is an object within the istream class.

Let’s have a deeper understanding through a piece of code

#include<iostream>
#include<string>
#include<cstdlib>
using namespace std;
class complex{
double real,imag;
public:
complex(double r=0,double i=0):real(r),imag(i){};//Constructor
friend ostream & amp;operator<<(ostream & amp;os,const complex & amp;c);//Declaration of the overload of the left shift operator. Operator overloading is also regarded as a function, so the friend keyword can also be used. Make it a friend function of the class
friend istream & amp;operator>>(istream & amp;is, complex & amp;c);
};
ostream & amp;operator<<(ostream & amp;os,const complex & amp;c)
{
os<<c.real<<" + "<<c.imag<<"i";
return os;
}
istream & amp;operator>>(istream & amp;is,complex & amp;c)
{
string s;
is>>s;
int pos=s.find(" + ",0);//Used to find characters or substrings in a string and return the first matching position
string sTmp=s.substr(0,pos);//Character interception function
c.real=atof(sTmp.c_str());//Convert the string into a floating point number
sTmp=s.substr(pos + 1,s.length()-pos-2);
c.imag=atof(sTmp.c_str());
return is;
}
int main()
{
complex c;
int n;
cin>>c>>n;
cout<<c<<","<<n;
return 0;
}

enter

11 12

output

11 + 1i,12

You can also copy the code and run it yourself for easier understanding.

Overloading of increment and decrement operators

Because auto-increment and auto-decrement operators are prefixed and postfixed, we distinguish them by the number of formal parameters.

1. Prefix operator overloading as a unary function

Overloaded as a member function of the class:

T opertor + + ();

T opertor–();

Overloaded as a global function:

T opertor + + (T);

T opertor–(T);

2. Postfix operators are overloaded as binary operators

Overloaded as a member function of the class:

T opertor + + (int);

T opertor–(int);

Overloaded as a global function:

T opertor + + (T,int);

T opertor–(T,int);

Use a piece of code to help understand

#include<iostream>
using namespace std;
class CDemo{
private:
int n;
public:
CDemo(int i=0):n(i){}
CDemo operator + + ();
CDemo operator + + (int);
operator int(){return n;}//Overloading of the type coercion operator, int(m) is equivalent to m.int(), the type coercion operator overload cannot write the return value type
friend CDemo operator--(CDemo & amp;);
friend CDemo operator--(CDemo & amp;,int);
};
CDemo CDemo::operator + + () {
n + + ;
return *this;
}
CDemo CDemo::operator + + (int k){
CDemo tmp(*this);
n + + ;
return tmp;
}
CDemo operator--(CDemo & amp;d){
d.n--;
return d;
}
CDemo operator--(CDemo & amp;d,int){
CDemo tmp(d);
d.n--;
return tmp;
}
int main(){
CDemo d(5);
cout<<(d + + )<<",";
cout<<d<<",";
cout<<( + + d)<<",";
cout<<d<<endl;
cout<<(d--)<<",";
cout<<d<<",";
cout<<(--d)<<",";
cout<<d<<endl;
return 0;
}

operation result

5,6,7,7
7,6,5,5

Notes on operator overloading

1. C++ does not allow the definition of new operators

2. The meaning of the overloaded operator should conform to daily habits.

3. Operator overloading cannot change the priority of the operator.

4. The following operators cannot be overloaded

“.” “.*” “::” “?:” sizeof

5. When overloading operators (), [], ->, =, the overloaded function must be declared as a member function of the class