Operator overloading (Part II)

Overloaded stream insertion operator "<" and stream extraction operator "> >

  • The C + + compilation system has overloaded < < and > >, which can be used as stream insertion operator and stream extraction operator to input and output C + + standard type data.
  • Data of self-defined types (such as class objects) cannot be directly output and input with "<" and "> >". If you want to use them to output and input data of your own declared types, you must overload them.
  • The overloaded function form of "<" and "> >" is as follows:
istream & operator>>(istream &,Custom class &);
ostream & operator<<(ostream &,Custom class &);

The first parameter and function type of the function of the overloaded operator "> >" must be istream & type (i.e. reference of istream class object), and the second parameter is the class for input operation; the first parameter and function type of the function of the overloaded operator "< <" must be ostream & type (i.e. reference of ostream class object), and the second parameter is the class for input operation.

  • Only functions overloaded with "> >" and "< <" can be regarded as friend functions, not member functions.

Overloaded stream insertion operator "< <"

Example: output complex numbers with overloaded operator "< <"

#include<iostream>
using namespace std;
class Complex
{
public:
	Complex() { real = 0; imag = 0; }
	Complex(double r, double i) { real = r; imag = i; }
	Complex operator+(Complex& c2); //The operator "+" is overloaded as a member function
	friend ostream& operator<<(ostream&, Complex&); //The operator "< <" is overloaded as a friend function
private:
	double real;
	double imag;
};

Complex Complex::operator+(Complex& c2) //Define operator '+' overloaded function
{
	return Complex(real + c2.real, imag + c2.imag);
}

ostream& operator<<(ostream& output, Complex& c) //Define operator '< <' overloaded function
{
	output << "(" << c.real << " + " << c.imag << "i)" << endl;
	return output;
}

int main()
{
	Complex c1(2, 4), c2(6, 10), c3;
	c3 = c1 + c2;
	cout << c3;
	return 0;
}

//Operation results:
(8 + 14i)

Program analysis:

  • Return output is used to continuously insert information into the output stream. Output is a reference to the object of the ostream class (it is a reference to the argument cout, or output is an alias of cout). Cout sends an address to output so that they share the same storage unit. Therefore, return output is return cout, which returns the current status of the output stream cout, that is, retains the current status of the output stream.

Overloaded stream insertion operator "> >"

#include<iostream>
using namespace std;
class Complex
{
public:
	friend ostream& operator<<(ostream&, Complex&); //Declaring friend overloaded operator "< <" function
	friend istream& operator>>(istream&, Complex&); //Declaring friend overloaded operator "> >" function
private:
	double real;
	double imag;
};

ostream& operator<<(ostream& output, Complex& c) //Define overloaded operator "< <" function
{
	output << "(" << c.real << " + " << c.imag << "i)";
	return output;
}

istream& operator>>(istream& input, Complex& c) //Define overloaded operator "> >" function
{
	cout << "input real part and imaginary part of complex number: ";
	input >> c.real >> c.imag;
	return input;
}

int main()
{
	Complex c1, c2;
	cin >> c1 >> c2;
	cout << "c1=" << c1 << endl;
	cout << "c2=" << c2 << endl;
	return 0;
}

Program analysis:

  • There are two "> >" in the cin statement. Every time "> >" is encountered, the function of overloaded operator "> >" is called. Therefore, the information prompted for input is output twice, and then the user is required to enter the value of the object.

Operation results:

Induction of operator overloading

  1. In C + +, operator overloading makes the class design more colorful, expands the function and scope of application of the class, makes the program easy to understand and operate the object, and embodies the idea of being considerate and convenient for users. With operator overloading, after declaring the class, we can use the operator for standard types for our declared class. The class declaration is once and for all. With a good class, users do not have to define many member functions in the program to complete some operations and input and output functions, making the main function easier to read. Good operator overloading can embody the idea of object-oriented programming.
  2. The specific methods of using operator overloading are as follows:
    ① To determine which operator is overloaded and which class to apply it to, overloaded operators can only use one operator for a specified class.
    ② Design operator overloaded functions and related classes (which contain operator overloaded member functions or friend function overloaded functions). The function of the function is completely specified by the designer to meet the user's requirements for using operators.
    ③ In practice, the end user is generally not required to write each operator overloaded function by himself. It is often someone who uniformly writes a batch of operator overloaded functions that need to be overloaded in the work of the field or the company, and puts them in a header file (the file name is determined by himself) and in the specified file directory for relevant people to use.
    ④ Users need to know which operator overloads are included in the header file, which classes are applicable to, and which parameters are available. That is to understand the prototype of overloaded functions of operators.
    ⑤ If there are special needs and no ready-made overloaded operators are available, you need to design your own operator overloaded functions. Care should be taken to keep the operator overloaded functions designed each time so that they will not be redesigned when they are used next time.
  3. The importance of using reference in operator overloading: using reference as the formal parameter of a function can combine virtual and real without passing value in the process of calling the function, and make the formal parameter become the alias of the actual parameter through address, without setting a formal parameter to store the value passed by the actual parameter, so the overhead of time and space is reduced. In addition, if the return value of an overloaded function is a reference to an object, instead of a constant, it refers to the object it represents. It can appear to the left of the assignment number and become an lvalue, which can be assigned or participate in other operations.

Conversion between different types of data

Conversion between standard type data

  • In C + +, some different data types can be automatically converted, such as:
int i = 6;
i = 7.5 + i;

This conversion is automatically completed by the C + + compilation system without user interference. This conversion is called implicit type conversion.

  • C + + also provides display type conversion in the form of type name (data); The form adopted in C language is: (type name) data

Use the conversion constructor to convert different types of data

  • The function of the conversion constructor is to convert another type of data into an object of a class.

  • Default constructor: the form of function prototype is: Complex()// No parameters

  • Constructor for initialization: the form of function prototype is: Complex(double r,double i)// There are usually more than two parameters in the formal parameter table column

  • Copy constructor for copying objects: the form of function prototype is: complex (complex &c)// Formal parameters are references to objects of this class

  • Conversion constructor: the conversion constructor has only one formal parameter, such as: complex (double R) {real = R; imag = 0;}
    Its function is to convert the parameter r of double type into the object of Complex class, and take r as the real part of the Complex number, and the imaginary part is 0.
    Note: the conversion constructor can only have one parameter. If there are multiple arguments, it is not a conversion constructor.

To sum up, the method of using the conversion constructor to convert a specified data into a class object is as follows:

  1. Declare a class first
  2. Define a constructor with only one parameter in this class. The type of parameter is the type to be converted. Specify the conversion method in the function body
  3. Within the scope of this class, type conversion can be carried out in the following form: class name (data of specified type), which can convert the data of specified type into objects of this class

Type conversion function

  • The function of type conversion is to convert an object of one class into data of another type.
  • The general form of type conversion function is:
operator Type name()
	{ Statement implementing conversion }

The function type cannot be specified before the function name. The function has no parameters. The type of its return value is determined by the type name specified in the function name. Type conversion functions can only be used as member functions, because the body of the conversion is the object of this class. Cannot be a friend function or an ordinary function.

Example: add a double data to the Complex data

#include<iostream>
using namespace std;
class Complex
{
public:
	Complex() { real = 0; imag = 0; }
	Complex(double r, double i) { real = r; imag = i; }
	operator double() { return real; } //Define type conversion function
private:
	double real;
	double imag;
};

int main()
{
	Complex c1(3, 4), c2(5, -10), c3; //Create three Complex class objects
	double d;
	d = 2.5 + c1; //It is required to add a double data to the Complex class data
	cout << d << endl;
	return 0;
}

//Operation result: 5.5

Overloaded functions use the keyword operator, which means "operator". Therefore, the type conversion function is usually also called type conversion operation function. Because it is also an overloaded function, it is also called type conversion operator overloaded function (or forced type conversion operator overloaded function)

Example: a program that contains conversion constructors, operator overloaded functions, and type conversion functions

#include<iostream>
using namespace std;
class Complex
{
public:
	Complex() { real = 0; imag = 0; } //Default constructor, invisible parameter
	Complex(double r) { real = r; imag = 0; } //Conversion constructor, a formal parameter
	Complex(double r, double i) { real = r; imag = i; }//Implement the initialized constructor with two formal parameters
	friend Complex operator+(Complex c1, Complex c2); //Overloaded friend function of operator '+'
	void display();
private:
	double real;
	double imag;
};
Complex operator+(Complex c1, Complex c2) //Define operator '+' overloaded function
{
	return Complex(c1.real + c2.real, c1.imag + c2.imag);
}
void Complex::display() //Define output function
{
	cout << "(" << real << "," << imag << "i)" << endl;
}
int main()
{
	Complex c1(3, 4), c2(5, -10), c3; //Create 3 objects
	c3 = c1 + 2.5; //Adding complex numbers to double data
	c3.display();
	return 0;
}

//Operation results: (5.5,4i)

When the corresponding conversion constructor has been defined, the operator "+" function is overloaded as a friend function. When adding two Complex numbers, the commutation law can be used. If the operator "+" overloaded function is not used as a friend function of the Complex class, but as a member function of the Complex class, the same result cannot be obtained.

Summary:

  1. If the operator function is overloaded as a member function, its first parameter must be an object of this class. Operator functions cannot be overloaded as member functions when the first operand is not a class object. If the operator "+" function is overloaded as a member function of a class, the commutative law does not apply
    For this reason, binocular operator functions are generally overloaded as friend functions. Unary operators are overloaded as member functions.
  2. If the operator must be overloaded as a member function, and the first operand is not a class object, there is only one way to solve it, and then overload an operator "+" function. Of course, this function can only be a friend function, which is obviously inconvenient.

Keywords: C++

Added by pelleas on Sat, 15 Jan 2022 10:50:30 +0200