1. What is Overloading?

Many textbook explanations and online definitions can be difficult to understand. In my own words:

C++ allows multiple definitions of functions and operators, similar to a word having multiple meanings. This is known as function overloading and operator overloading. You can use functions with the same name or the same operator to achieve different effects.

(1) Function Overloading in C++

In the same scope, there can be a group of functions with the same name but different parameter lists. These functions are similar in purpose, but their parameters differ. Such a group of functions is called overloaded functions.

Role: Function overloading reduces the number of unique function names, preventing name-space pollution and improving the readability of the code.

(2) Operator Overloading in C++

In C++ programs, we can redefine and overload many built-in operators, allowing for custom behaviour. Overloaded operators must have special function names, using the keyword operator. The keyword operator must be followed by the symbol of the operator to be overloaded, along with a return type and a parameter list, as shown below:

1
ComplexNumber operator+(ComplexNumber z);

However, certain operators in C++ cannot be overloaded. The following table lists non-overloadable operators:

Non-overloadable operator Statement
. Member access operator
.* and ->* Member pointer access operator
:: Scope resolution operator
sizeof Length operator
?: Conditional operator
# Preprocessor symbol

2. Complex Numbers (Partial Knowledge)

(1) Definition and Concept of Complex Numbers

A complex number is expressed in the form a + bi, where a and b are real numbers, and i represents the solution to the equation x² = -1. Since no real number satisfies this equation, i is known as an imaginary number. In the complex number a + bi, a is the real part, and b is the imaginary part. Despite the historical term “imaginary,” complex numbers are as “real” as real numbers in the mathematical sciences and form the foundation of many scientific descriptions of natural phenomena.

Complex numbers can solve certain equations that have no real-number solutions. For example, the equation (x + 1)² = -9 has no real-number solution because the square of a real number cannot be negative. However, complex numbers extend real numbers with the imaginary unit i, satisfying i² = -1, which enables us to find the solutions: -1 + 3i and -1 - 3i.

(2) Geometric Representation of Complex Numbers

Geometrically, complex numbers extend the concept of a one-dimensional number line to a two-dimensional complex plane, where the horizontal axis represents the real part and the vertical axis represents the imaginary part. A complex number a + bi can be represented as the point (a, b) in the complex plane. Complex numbers with a real part of zero are called pure imaginary numbers and are represented as points on the vertical axis. Conversely, complex numbers with an imaginary part of zero are regarded as real numbers and are represented on the horizontal axis. Complex numbers can also be expressed in polar coordinates, which associate each complex number with its distance from the origin (its magnitude) and a specific angle (called the argument).

Complex numbers can be represented visually as a vector in the complex plane. “Re” is the real axis, and “Im” is the imaginary axis, with i satisfying i² = -1. The key points are:

  1. The complex number z = a + bi corresponds to the point (a, b) in the complex plane.
  2. The complex number z = a + bi corresponds to the vector OZ, where the coordinates of point Z are (a, b).

(3) Addition and Subtraction of Complex Numbers

Addition of two complex numbers:

[
(x + yi) + (u + vi) = (x + u) + (y + v)i
]

Subtraction of two complex numbers:

[
(x + yi) - (u + vi) = (x - u) + (y - v)i
]

Geometrically, we can visualise the addition of two complex numbers by constructing a parallelogram. In the complex plane, the sum of two complex numbers a and b corresponds to a point obtained by constructing a parallelogram with the vectors O, a, and b as three vertices. The point X forms the fourth vertex of the parallelogram, with triangles OAB and XBA being congruent. The visualisation of subtraction can be achieved by considering negative vectors.

(4) Multiplication and Division of Complex Numbers

Multiplication of complex numbers:

[
(x + yi) \times (u + vi) = (xu - yv) + (xv + yu)i
]

Division of complex numbers:
To divide complex numbers, we use the conjugate. Conjugate complex numbers have equal real parts and opposite imaginary parts. If the imaginary part is zero, the conjugate complex number is itself. The conjugate of a complex number z is denoted as (\overline{z}) (or sometimes as Z*). The conjugate is used in the formula for calculating the reciprocal of a non-zero complex number:

This can be used to represent the division of any complex number (where z is not equal to 0):

3. Friend Function in C++

A friend function is not a member of a class but can access all of the class’s members. It is granted the privilege to access private and protected members of a class. A friend can be either a function or a class, and we call them friend functions and friend classes, respectively. Since the friend class concept is not relevant to our current project, we will not explore it here.

Role: Suppose you are a developer working with a library project and wish to practise accessing its code. Often, private and protected members are not accessible. However, if the class includes a friend function, it means that you can access those members via that function.

Keyword: friend
To declare a function as a friend of a class, use the friend keyword before the function definition in the class declaration, as shown below:

1
friend ComplexNumber operator+(const float a, const ComplexNumber &z);

4. Design and Implementation

(1) Program Structure and Design Concept

For this program, I first created a complex number class. In the private members of the class, I used double-precision floating-point numbers to define the real and imaginary parts. I also provided overloaded functions as public members to allow users to input the real and imaginary parts into the system. Three cases are considered: both the real and imaginary parts are given, neither is given, or only the imaginary part is provided. By default, both the real and imaginary parts are initialised to zero.

In the public members, I also included a function for adding the real and imaginary parts, enabling the storage and conversion of values. The setting function operates similarly. Additionally, I wrote an output function that includes a conditional statement to check whether the imaginary part is greater than or equal to zero, preventing redundant negative signs in the output.

Finally, I implemented overloading for the four basic arithmetic operations as well as the input and output operators. The addition operator is overloaded in two different ways. (While class templates may also be an option, here I focus on overloading functions and operators.) Input, output, and addition are implemented as friend functions to allow direct access to private members. A test function is then written outside the class, which is invoked in the main function.

(2) Correspondence between Functions and Source Code

When outputting, a check is performed to determine whether the imaginary part is greater than or equal to zero to prevent redundant negative signs.

1
2
3
4
5
6
7
8
void ComplexNumber::Show()
{
if(im>=0)
cout <<"("<< re << "+" << im <<"i)";
else
cout <<"("<< setiosflags(ios::fixed) << setprecision(2) << re << "+" << im << "i" <<")";

};

Implementation of complex multiplication (overload of multiplication operator):

1
2
3
4
5
6
7
ComplexNumber ComplexNumber::operator *(ComplexNumber z)
{
ComplexNumber tmp;
tmp.re=re*z.re-(im*z.im);
tmp.im=im*z.re+re*z.im;
return tmp;
}

Implementation of complex division operation (overload of division operator):

1
2
3
4
5
6
7
ComplexNumber ComplexNumber::operator/(ComplexNumber z)
{
ComplexNumber tmp;
tmp.re=(re*z.re+im*z.im)/(z.re*z.re+z.im*z.im);
tmp.im=(im*z.re-re*z.im)/(z.re*z.re+z.im*z.im);
return tmp;
}

Overloading of output operators:

1
2
3
4
5
6
7
8
9
10
ostream & operator << (ostream & a,const ComplexNumber & z)
{
if(z.re==0&&z.im==0)a << setiosflags(ios::fixed) << setprecision(0) << z.re;
else if(z.im==0)a << setiosflags(ios::fixed) << setprecision(0) << z.re ;
else if(z.im>0)
a << setiosflags(ios::fixed) << setprecision(2) << z.re << "+" << z.im << "i";
else if(z.im<0)
a << setiosflags(ios::fixed) << setprecision(2) << z.re << z.im << "i";
return a;
}

Test input function:

1
2
3
4
5
6
7
8
9
10
void CN() 
{
//ComplexNumber
ComplexNumber cn1, cn2;
std::cin >> cn1 >> cn2;
std::cout<<cn1+cn2 << std::endl;
std::cout<<cn1 - cn2 << std::endl;
std::cout<<cn1*cn2 << std::endl;
std::cout<<cn1 / cn2 << std::endl;
}

(3). Overall source code

The overall source code is as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
#include <iostream>
#include <iomanip>
using namespace std;
class ComplexNumber
{
private:
double im,re;
public:
ComplexNumber(double i=0, double r=0);
// ComplexNumber();
// ComplexNumber(int i);
ComplexNumber Add(ComplexNumber z);
ComplexNumber operator+(ComplexNumber z);
friend ComplexNumber operator+(const float a, const ComplexNumber &z);
friend istream & operator >> (istream & b, ComplexNumber &z);
friend ostream & operator << (ostream & a,const ComplexNumber & z);
ComplexNumber operator-(ComplexNumber z);
ComplexNumber operator*(ComplexNumber z);
ComplexNumber operator/(ComplexNumber z);
double Set(double x, double y);
void Show();

};
ComplexNumber::ComplexNumber(double i, double r)
{
im=r;
re=i;
}
/*ComplexNumber::ComplexNumber()
{
im=0;
re=0;
}
ComplexNumber::ComplexNumber(int i)
{
im=i;
re=0;
}*/

void ComplexNumber::Show()
{
if(im>=0)
cout <<"("<< re << "+" << im <<"i)";
else
cout <<"("<< setiosflags(ios::fixed) << setprecision(2) << re << "+" << im << "i" <<")";

};
ComplexNumber ComplexNumber::Add(ComplexNumber z)
{
ComplexNumber tmp;
tmp.re=re+z.re;
tmp.im=im+z.im;
return tmp;
}
ComplexNumber ComplexNumber::operator +(ComplexNumber z)
{
ComplexNumber tmp;
tmp.re=re+z.re;
tmp.im=im+z.im;
return tmp;
}
ComplexNumber operator +(const float a,const ComplexNumber &z)
{
ComplexNumber tmp;
tmp.re=a+z.re;
tmp.im=z.im;
return tmp;
}
ComplexNumber ComplexNumber::operator -(ComplexNumber z)
{
ComplexNumber tmp;
tmp.re=re-z.re;
tmp.im=im-z.im;
return tmp;
}
ComplexNumber ComplexNumber::operator *(ComplexNumber z)
{
ComplexNumber tmp;
tmp.re=re*z.re-(im*z.im);
tmp.im=im*z.re+re*z.im;
return tmp;
}
ComplexNumber ComplexNumber::operator/(ComplexNumber z)
{
ComplexNumber tmp;
tmp.re=(re*z.re+im*z.im)/(z.re*z.re+z.im*z.im);
tmp.im=(im*z.re-re*z.im)/(z.re*z.re+z.im*z.im);
return tmp;
}
double ComplexNumber::Set(double x, double y)
{
im=y;
re=x;
return im,re;
}
istream & operator>>(istream & b, ComplexNumber &z)
{
b >> z.re >> z.im;
return b;
}
ostream & operator << (ostream & a,const ComplexNumber & z)
{
if(z.re==0&&z.im==0)a << setiosflags(ios::fixed) << setprecision(0) << z.re;
else if(z.im==0)a << setiosflags(ios::fixed) << setprecision(0) << z.re ;
else if(z.im>0)
a << setiosflags(ios::fixed) << setprecision(2) << z.re << "+" << z.im << "i";
else if(z.im<0)
a << setiosflags(ios::fixed) << setprecision(2) << z.re << z.im << "i";
return a;
}

void CN()
{
//ComplexNumber
ComplexNumber cn1, cn2;
std::cin >> cn1 >> cn2;
std::cout<<cn1+cn2 << std::endl;
std::cout<<cn1 - cn2 << std::endl;
std::cout<<cn1*cn2 << std::endl;
std::cout<<cn1 / cn2 << std::endl;
}
int main(void)
{
CN();
return 0;
}

Copyright Notice
This article, except for the referenced content below, is the original work of Junhao. The author retains the exclusive rights to its final interpretation. If there are any issues regarding copyright infringement, please contact me for removal. Reproduction or distribution of this content without my explicit permission is prohibited.

5. References

[1]. CppReference https://en.cppreference.com/w/cpp/language/operators

[2]. GeeksForGeeks https://www.geeksforgeeks.org/function-overloading-c/

[3]. Wikipedia https://en.wikipedia.org/wiki/Complex_number#Addition_and_subtraction

[4]. Runoob https://www.runoob.com/cplusplus/cpp-overloading.html

[5]. Runoob https://www.runoob.com/cplusplus/cpp-friend-functions.html

[6]. 360Doc http://www.360doc.com/content/19/0118/12/46601607_809660209.shtml