CPP Operator Overloading A3
CPP Operator Overloading A3
CPP Operator Overloading A3
Example
1 /* Test overloaded operators in the C++ string class
2 (TestStringOverloadOperators.cpp) */
3 #include <iostream>
4 #include <iomanip>
5 #include <string> // needed to use the string class
6 using namespace std;
7
8 int main() {
9 string msg1("hello");
10 string msg2("HELLO");
11 string msg3("hello");
12
13 // Relational Operators (comparing the contents)
14 cout << boolalpha;
15 cout << (msg1 == msg2) << endl; // false
16 cout << (msg1 == msg3) << endl; // true
17 cout << (msg1 < msg2) << endl; // false (uppercases before lowercases)
18
19 // Assignment
20 string msg4 = msg1;
21 cout << msg4 << endl; // hello
22
23 // Concatenation
24 cout << (msg1 + " " + msg2) << endl; // hello HELLO
25 msg3 += msg2;
26 cout << msg3 << endl; // helloHELLO
27
28 // Indexing
29 cout << msg1[1] << endl; // 'e'
30 cout << msg1[99] << endl; // garbage (no index-bound check)
31 // cout << msg1.at(99) << endl; // out_of_range exception
1 of 17 22/03/2020, 19:45
Object-oriented Programming (OOP) in C++ https://www3.ntu.edu.sg/home/ehchua/programming/cpp/cp7_Operator...
32 }
Notes : The rela�onal operators (==, !=, >, <, >=, <=), +, <<, >> are overloaded as non-member func�ons, where the le� operand could be a non-string
object (such as C-string, cin, cout); while =, [], += are overloaded as member func�ons where the le� operand must be a string object. I shall elaborate
later.
return-type operatorΔ(parameter-list)
For example, operator+() overloads the + operator; operator<<() overloads the << operator. Take note that Δ must be an exis�ng C++ operator. You
cannot create you own operator.
2.2 Example: Overloading '+' Operator for the Point Class as Member Function
In this example, we shall overload the '+' operator in the Point class to support addi�on of two Point objects. In other words, we can write p3 = p1+p2,
where p1, p2 and p3 are Point objects, similar to the usual arithme�c opera�on. We shall construct a new Point instance p3 for the sum, without changing
the p1 and p2 instances.
Point.h
/* The Point class Header file (Point.h) */
1
#ifndef POINT_H
2
#define POINT_H
3
4
class Point {
5
private:
6
int x, y; // Private data members
7
8
public:
9
Point(int x = 0, int y = 0); // Constructor
10
int getX() const; // Getters
11
int getY() const;
12
void setX(int x); // Setters
13
void setY(int y);
14
void print() const;
15
const Point operator+(const Point & rhs) const;
16
// Overload '+' operator as member function of the class
17
};
18
19
#endif
Program Notes:
We overload the + operator via a member func�on operator+(), which shall add this instance (le� operand) with the rhs operand, construct a new
instance containing the sum and and return it by value. We cannot return by reference a local variable created inside the func�on, as the local variable
would be destroyed when the func�on exits.
The rhs operand is passed by reference for performance.
The member func�on is declared const, which cannot modify data members.
The return value is declared const, so as to prevent it from being used as lvalue. For example, it prevents wri�ng (p1+p2) = p3, which is meaningless
and could be due to misspelling (p1+p2) == p3.
Point.cpp
1 /* The Point class Implementation file (Point.cpp) */
2 #include "Point.h"
3 #include <iostream>
4 using namespace std;
5
6 // Constructor - The default values are specified in the declaration
7 Point::Point(int x, int y) : x(x), y(y) { } // Using initializer list
8
9 // Getters
10 int Point::getX() const { return x; }
11 int Point::getY() const { return y; }
12
13 // Setters
14 void Point::setX(int x) { this->x = x; }
2 of 17 22/03/2020, 19:45
Object-oriented Programming (OOP) in C++ https://www3.ntu.edu.sg/home/ehchua/programming/cpp/cp7_Operator...
Program Notes:
The func�on allocates a new Point object with the sums of x's and y's, and returns this object by const value.
TestPoint.cpp
1 #include "Point.h"
2 #include <iostream>
3 using namespace std;
4
5 int main() {
6 Point p1(1, 2), p2(4, 5);
7 // Use overloaded operator +
8 Point p3 = p1 + p2;
9 p1.print(); // (1,2)
10 p2.print(); // (4,5)
11 p3.print(); // (5,7)
12
13 // Invoke via usual dot syntax, same as p1+p2
14 Point p4 = p1.operator+(p2);
15 p4.print(); // (5,7)
16
17 // Chaining
18 Point p5 = p1 + p2 + p3 + p4;
19 p5.print(); // (15,21)
20 }
Program Notes:
You can invoke the overloaded operator via p1+p2, which will be translated into the dot opera�on p1.operator+(p2).
The + operator supports chaining (cascading) opera�ons, as p1+p2 returns a Point object.
3.1 Why can't we always use Member Function for Operator Overloading?
The member func�on operatorΔ() can only be invoked from an object via the dot operator, e.g., p1.operatorΔ(p2), which is equivalent to p1 Δ p2.
Clearly the le� operand p1 should be an object of that par�cular class. Suppose that we want to overload a binary operator such as * to mul�ply the object p1
with an int literal, p1*5 can be translated into p1.operator*(5), but 5*p1 cannot be represented using member func�on. One way to deal with this
problem is only allow user to write p1*5 but not 5*p1, which is not user friendly and break the rule of commuta�vity. Another way is to use a non-member
func�on, which does not invoke through an object and dot operator, but through the arguments provided. For example, 5*p1 could be translated to
operator+(5, p1).
In brief, you cannot use member func�on to overload an operator if the le� operand is not an object of that par�cular class.
A "friend" func�on of a class, marked by the keyword friend, is a func�on defined outside the class, yet its argument of that class has unrestricted access to
all the class members (private, protected and public data members and member func�ons). Friend func�ons can enhance the performance, as they
3 of 17 22/03/2020, 19:45
Object-oriented Programming (OOP) in C++ https://www3.ntu.edu.sg/home/ehchua/programming/cpp/cp7_Operator...
eliminate the need of calling public member func�ons to access the private data members.
3.3 Example: Overloading << and >> Operators of Point class using non-member friend
Functions
In this example, we shall overload << and >> operators to support stream inser�on and extrac�on of Point objects, i.e., cout << aPoint, and cin >>
aPoint. Since the le� operand is not a Point object (cout is an ostream object and cin is an istream object), we cannot use member func�on, but
need to use non-member func�on for operator overloading. We shall make these func�ons friends of the Point class, to allow them to access the private
data members directly for enhanced performance.
Point.h
1 /* The Point class Header file (Point.h) */
2 #ifndef POINT_H
3 #define POINT_H
4
5 #include <iostream>
6
7 // Class Declaration
8 class Point {
9 private:
10 int x, y;
11
12 public:
13 Point(int x = 0, int y = 0);
14 int getX() const; // Getters
15 int getY() const;
16 void setX(int x); // Setters
17 void setY(int y);
18
19 friend std::ostream & operator<<(std::ostream & out, const Point & point);
20 friend std::istream & operator>>(std::istream & in, Point & point);
21 };
22
23 #endif
Program Notes:
Friends are neither public or private, and can be listed anywhere within the class declara�on.
The cout and cin need to be passed into the func�on by reference, so that the func�on accesses the cout and cin directly (instead of a clone copy by
value).
We return the cin and cout passed into the func�on by reference too, so as to support cascading opera�ons. For example, cout << p1 << endl
will be interpreted as (cout << p1) << endl.
In <<, the reference parameter Point is declared as const. Hence, the func�on cannot modify the Point object. On the other hand, in >>, the Point
reference is non-const, as it will be modified to keep the input.
We use fully-qualified name std::istream instead of placing a "using namespace std;" statement in the header. It is because this header could
be included in many files, which would include the using statement too and may not be desirable.
Point.cpp
1 /* The Point class Implementation file (Point.cpp) */
2 #include <iostream>
3 #include "Point.h"
4 using namespace std;
5
6 // Constructor - The default values are specified in the declaration
7 Point::Point(int x, int y) : x(x), y(y) { } // using member initializer list
8
9 // Getters
10 int Point::getX() const { return x; }
11 int Point::getY() const { return y; }
12
13 // Setters
14 void Point::setX(int x) { this->x = x; }
15 void Point::setY(int y) { this->y = y; }
16
17 ostream & operator<<(ostream & out, const Point & point) {
18 out << "(" << point.x << "," << point.y << ")"; // access private data
19 return out;
20 }
21
22 istream & operator>>(istream & in, Point & point) {
23 cout << "Enter x and y coord: ";
24 in >> point.x >> point.y; // access private data
4 of 17 22/03/2020, 19:45
Object-oriented Programming (OOP) in C++ https://www3.ntu.edu.sg/home/ehchua/programming/cpp/cp7_Operator...
25 return in;
26 }
Program Notes:
The func�on defini�on does not require the keyword friend, and the ClassName:: scope resolu�on qualifier, as it does not belong to the class.
The operator<<() func�on is declared as a friend of Point class. Hence, it can access the private data members x and y of its argument Point
directly. operator<<() func�on is NOT a friend of ostream class, as there is no need to access the private member of ostream.
Instead of accessing private data member x and y directly, you could use public member func�on getX() and getY(). In this case, there is no need to
declare operator<<() as a friend of the Point class. You could simply declare a regular func�on prototype in the header.
// Function prototype
ostream & operator<<(ostream & out, const Point & point);
// Function definition
ostream & operator<<(ostream & out, const Point & point) {
out << "(" << point.getX() << "," << point.getY() << ")";
return out;
}
Using friend is recommended, as it enhances performance. Furthermore, the overloaded operator becomes part of the extended public interface of the
class, which helps in ease-of-use and ease-of-maintenance.
TestPoint.cpp
1 #include <iostream>
2 #include "Point.h"
3 using namespace std;
4
5 int main() {
6 Point p1(1, 2), p2;
7
8 // Using overloaded operator <<
9 cout << p1 << endl; // support cascading
10 operator<<(cout, p1); // same as cout << p1
11 cout << endl;
12
13 // Using overloaded operator >>
14 cin >> p1;
15 cout << p1 << endl;
16 operator>>(cin, p1); // same as cin >> p1
17 cout << p1 << endl;
18 cin >> p1 >> p2; // support cascading
19 cout << p1 << endl;
20 cout << p2 << endl;
21 }
The overloaded >> and << can also be used for file input/output, as the file IO stream ifstream/ofstream (in fstream header) is a subclass of
istream/ostream. For example,
#include <fstream>
#include "Point.h"
using namespace std;
int main() {
Point p1(1, 2);
ofstream fout("out.txt");
fout << p1 << endl;
Suppose that we wish to overload the binary operator == to compare two Point objects. We could do it as a member func�on or non-member func�on.
5 of 17 22/03/2020, 19:45
Object-oriented Programming (OOP) in C++ https://www3.ntu.edu.sg/home/ehchua/programming/cpp/cp7_Operator...
class Point {
public:
bool operator==(const Point & rhs) const; // p1.operator==(p2)
......
};
The compiler translates "p1 == p2" to "p1.operator==(p2)", as a member func�on call of object p1, with argument p2.
Member func�on can only be used if the le� operand is an object of that par�cular class.
2. To overload as a non-member func�on, which is o�en declared as a friend to access the private data for enhanced performance, the declara�on is as
follows:
class Point {
friend bool operator==(const Point & lhs, const Point & rhs); // operator==(p1,p2)
......
};
class Point {
friend Point & operator++(Point & point);
......
};
class Point {
public:
Point & operator++(); // this Point
......
};
You can use either member func�on or non-member friend func�on to overload unary operators, as their only operand shall be an object of that class.
class Point {
friend const Point operator++(Point & point, int dummy);
};
The compiler translates "pt++" to "operator++(pt, 0)". The int argument is strictly a dummy value to differen�ate prefix from pos�ix opera�on.
2. To overload as a member func�on:
class Point {
public:
const Point operator++(int dummy); // this Point
......
};
5.3 Example: Overloading Prefix and Postfix ++ for the Counter Class
Counter.h
6 of 17 22/03/2020, 19:45
Object-oriented Programming (OOP) in C++ https://www3.ntu.edu.sg/home/ehchua/programming/cpp/cp7_Operator...
Program Notes:
The prefix func�on returns a reference to this instance, to support chaining (or cascading), e.g., ++++c as ++(++c). However, the return reference can be
used as lvalue with unexpected opera�ons (e.g., ++c = 8).
The pos�ix func�on returns a const object by value. A const value cannot be used as lvalue. This prevents chaining such as c++++. Although it would
be interpreted as (c++)++. However, (c++) does not return this object, but an temporary object. The subsequent ++ works on the temporary object.
Both prefix and pos�ix func�ons are non-const, as they modify the data member count.
Counter.cpp
1 /* The Counter class Implementation file (Counter.cpp) */
2 #include "Counter.h"
3 #include <iostream>
4 using namespace std;
5
6 // Constructor - The default values are specified in the declaration
7 Counter::Counter(int c) : count(c) { } // using member initializer list
8
9 // Getters
10 int Counter::getCount() const { return count; }
11
12 // Setters
13 void Counter::setCount(int c) { count = c; }
14
15 // ++prefix, return reference of this
16 Counter & Counter::operator++() {
17 ++count;
18 return *this;
19 }
20
21 // postfix++, return old value by value
22 const Counter Counter::operator++(int dummy) {
23 Counter old(*this);
24 ++count;
25 return old;
26 }
27
28 // Overload stream insertion << operator
29 ostream & operator<<(ostream & out, const Counter & counter) {
30 out << counter.count;
31 return out;
32 }
Program Notes:
The prefix func�on increments the count, and returns this object by reference.
The pos�ix func�on saves the old value (by construc�ng a new instance with this object via the copy constructor), increments the count, and return the
saved object by value.
Clearly, pos�ix opera�on on object is less efficient than the prefix opera�on, as it create a temporary object. If there is no subsequent opera�on that relies
on the output of prefix/pos�ix opera�on, use prefix opera�on.
TestCounter.cpp
1 #include "Counter.h"
2 #include <iostream>
7 of 17 22/03/2020, 19:45
Object-oriented Programming (OOP) in C++ https://www3.ntu.edu.sg/home/ehchua/programming/cpp/cp7_Operator...
Program Notes:
Take note of the difference in cout << c1++ and cout << ++c1. Both prefix and pos�ix operators work as expected.
++++c1 is allowed and works correctly. c1++++ is disallowed, because it would produce incorrect result.
Point.h
1 /* The Point class Header file (Point.h) */
2 #ifndef POINT_H
3 #define POINT_H
4 #include <iostream>
5
6 class Point {
7 private:
8 int x, y;
9
10 public:
11 explicit Point(int x = 0, int y = 0);
12 int getX() const;
13 int getY() const;
14 void setX(int x);
15 void setY(int y);
16 Point & operator++(); // ++prefix
17 const Point operator++(int dummy); // postfix++
18 const Point operator+(const Point & rhs) const; // Point + Point
19 const Point operator+(int value) const; // Point + int
20 Point & operator+=(int value); // Point += int
21 Point & operator+=(const Point & rhs); // Point += Point
22
23 friend std::ostream & operator<<(std::ostream & out, const Point & point); // out << point
24 friend std::istream & operator>>(std::istream & in, Point & point); // in >> point
25 friend const Point operator+(int value, const Point & rhs); // int + Point
26 };
27
28 #endif
Point.cpp
1 /* The Point class Implementation file (Point.cpp) */
2 #include "Point.h"
3 #include <iostream>
4 using namespace std;
5
6 // Constructor - The default values are specified in the declaration
7 Point::Point(int x, int y) : x(x), y(y) { }
8
9 // Getters
10 int Point::getX() const { return x; }
11 int Point::getY() const { return y; }
12
13 // Setters
14 void Point::setX(int x) { this->x = x; }
15 void Point::setY(int y) { this->y = y; }
16
17 // Overload ++Prefix, increase x, y by 1
18 Point & Point::operator++() {
19 ++x;
8 of 17 22/03/2020, 19:45
Object-oriented Programming (OOP) in C++ https://www3.ntu.edu.sg/home/ehchua/programming/cpp/cp7_Operator...
20 ++y;
21 return *this;
22 }
23
24 // Overload Postfix++, increase x, y by 1
25 const Point Point::operator++(int dummy) {
26 Point old(*this);
27 ++x;
28 ++y;
29 return old;
30 }
31
32 // Overload Point + int. Return a new Point by value
33 const Point Point::operator+(int value) const {
34 return Point(x + value, y + value);
35 }
36
37 // Overload Point + Point. Return a new Point by value
38 const Point Point::operator+(const Point & rhs) const {
39 return Point(x + rhs.x, y + rhs.y);
40 }
41
42 // Overload Point += int. Increase x, y by value
43 Point & Point::operator+=(int value) {
44 x += value;
45 y += value;
46 return *this;
47 }
48
49 // Overload Point += Point. Increase x, y by rhs
50 Point & Point::operator+=(const Point & rhs) {
51 x += rhs.x;
52 y += rhs.y;
53 return *this;
54 }
55
56 // Overload << stream insertion operator
57 ostream & operator<<(ostream & out, const Point & point) {
58 out << "(" << point.x << "," << point.y << ")";
59 return out;
60 }
61
62 // Overload >> stream extraction operator
63 istream & operator>>(istream & in, Point & point) {
64 cout << "Enter x and y coord: ";
65 in >> point.x >> point.y;
66 return in;
67 }
68
69 // Overload int + Point. Return a new point
70 const Point operator+(int value, const Point & rhs) {
71 return rhs + value; // use member function defined above
72 }
TestPoint.cpp
1 #include <iostream>
2 #include "Point.h"
3 using namespace std;
4
5 int main() {
6 Point p1(1, 2);
7 cout << p1 << endl; // (1,2)
8
9 Point p2(3,4);
10 cout << p1 + p2 << endl; // (4,6)
11 cout << p1 + 10 << endl; // (11,12)
12 cout << 20 + p1 << endl; // (21,22)
13 cout << 10 + p1 + 20 + p1 << endl; // (32,34)
14
15 p1 += p2;
16 cout << p1 << endl; // (4,6)
17 p1 += 3;
18 cout << p1 << endl; // (7,9)
19
20 Point p3; // (0,0)
9 of 17 22/03/2020, 19:45
Object-oriented Programming (OOP) in C++ https://www3.ntu.edu.sg/home/ehchua/programming/cpp/cp7_Operator...
1 #include <iostream>
2 using namespace std;
3
4 class Counter {
5 private:
6 int count;
7 public:
8 Counter(int c = 0) : count(c) { }
9 // A single-argument Constructor which takes an int
10 // It can be used to implicitly convert an int to a Counter object
11 int getCount() const { return count; } // Getter
12 void setCount(int c) { count = c; } // Setter
13 };
14
15 int main() {
16 Counter c1; // Declare an instance and invoke default constructor
17 cout << c1.getCount() << endl; // 0
18
19 c1 = 9;
20 // Implicit conversion
21 // Invoke single-argument constructor Counter(9) to construct a temporary object.
22 // Then copy into c1 via memberwise assignment.
23 cout << c1.getCount() << endl; // 9
24 }
This implicit conversion can be confusing. C++ introduces a keyword "explicit" to disable implicit conversion. Nonetheless, you can s�ll perform explicit
conversion via type cast operator. For example,
1 #include <iostream>
2 using namespace std;
3
4 class Counter {
5 private:
6 int count;
7 public:
8 explicit Counter(int c = 0) : count(c) { }
9 // Single-argument Constructor
10 // Use keyword "explicit" to disable implicit automatic conversion in assignment
11 int getCount() const { return count; } // Getter
12 void setCount(int c) { count = c; } // Setter
13 };
14
15 int main() {
16 Counter c1; // Declare an instance and invoke default constructor
17 cout << c1.getCount() << endl; // 0
18
19 // Counter c2 = 9;
20 // error: conversion from 'int' to non-scalar type 'Counter' requested
21
22 c1 = (Counter)9; // Explicit conversion via type casting operator
23 cout << c1.getCount() << endl; // 9
24 }
MyComplex.h
1 /*
2 * The MyComplex class header (MyComplex.h)
3 * Follow, modified and simplified from GNU GCC complex template class
10 of 17 22/03/2020, 19:45
Object-oriented Programming (OOP) in C++ https://www3.ntu.edu.sg/home/ehchua/programming/cpp/cp7_Operator...
4 */
5 #ifndef MY_COMPLEX_H
6 #define MY_COMPLEX_H
7
8 #include <iostream>
9
10 class MyComplex {
11 private:
12 double real, imag;
13
14 public:
15 explicit MyComplex (double real = 0, double imag = 0); // Constructor
16 MyComplex & operator+= (const MyComplex & rhs); // c1 += c2
17 MyComplex & operator+= (double real); // c += double
18 MyComplex & operator++ (); // ++c
19 const MyComplex operator++ (int dummy); // c++
20 bool operator== (const MyComplex & rhs) const; // c1 == c2
21 bool operator!= (const MyComplex & rhs) const; // c1 != c2
22
23 // friends
24 friend std::ostream & operator<< (std::ostream & out, const MyComplex & c); // out << c
25 friend std::istream & operator>> (std::istream & in, MyComplex & c); // in >> c
26 friend const MyComplex operator+ (const MyComplex & lhs, const MyComplex & rhs); // c1 + c2
27 friend const MyComplex operator+ (double real, const MyComplex & rhs); // double + c
28 friend const MyComplex operator+ (const MyComplex & lhs, double real); // c + double
29 };
30
31 #endif
32
Program Notes:
I prefer to list the private sec�on before the public sec�on in the class declara�on to have a quick look at the internal of the class for ease of
understanding.
I named the private data members real and imag, that poten�ally crash with the func�on parameters. I resolves the crashes via this-> pointer if
needed. Some people suggest to name private data members with a trailing underscore (e.g., real_, imag_) to dis�nguish from the func�on
parameters. As private members are not expose to the users, strange names are acceptable. The C++ compiler uses leading underscore(s) to name its
variables internally (_xxx for data members, __xxx for local variables).
The constructor is declared explicit. This is because a single-argument constructor can be used for implicit conversion, in this case, from double to
MyComplex, e.g.,
// Without explicit
MyComplex c = 5.5; // Same as MyComplex c = (MyComplex)5.5;
// With explicit
MyComplex c = 5.5;
// error: conversion from 'double' to non-scalar type 'MyComplex' requested
MyComplex c = (MyComplex)5.5; // Okay
11 of 17 22/03/2020, 19:45
Object-oriented Programming (OOP) in C++ https://www3.ntu.edu.sg/home/ehchua/programming/cpp/cp7_Operator...
MyComplex.cpp
1 /* The MyComplex class implementation (MyComplex.cpp) */
2 #include "MyComplex.h"
3
4 // Constructor
5 MyComplex::MyComplex (double r, double i) : real(r), imag(i) { }
6
7 // Overloading += operator for c1 += c2
8 MyComplex & MyComplex::operator+= (const MyComplex & rhs) {
9 real += rhs.real;
10 imag += rhs.imag;
11 return *this;
12 }
13
14 // Overloading += operator for c1 += double (of real)
15 MyComplex & MyComplex::operator+= (double value) {
16 real += value;
17 return *this;
18 }
19
20 // Overload prefix increment operator ++c (real part)
21 MyComplex & MyComplex::operator++ () {
22 ++real; // increment real part only
23 return *this;
24 }
25
26 // Overload postfix increment operator c++ (real part)
27 const MyComplex MyComplex::operator++ (int dummy) {
28 MyComplex saved(*this);
29 ++real; // increment real part only
30 return saved;
31 }
32
33 // Overload comparison operator c1 == c2
34 bool MyComplex::operator== (const MyComplex & rhs) const {
35 return (real == rhs.real && imag == rhs.imag);
36 }
37
38 // Overload comparison operator c1 != c2
39 bool MyComplex::operator!= (const MyComplex & rhs) const {
40 return !(*this == rhs);
41 }
42
43 // Overload stream insertion operator out << c (friend)
44 std::ostream & operator<< (std::ostream & out, const MyComplex & c) {
45 out << '(' << c.real << ',' << c.imag << ')';
46 return out;
47 }
48
49 // Overload stream extraction operator in >> c (friend)
50 std::istream & operator>> (std::istream & in, MyComplex & c) {
51 double inReal, inImag;
52 char inChar;
53 bool validInput = false;
54 // Input shall be in the format "(real,imag)"
55 in >> inChar;
56 if (inChar == '(') {
57 in >> inReal >> inChar;
58 if (inChar == ',') {
59 in >> inImag >> inChar;
60 if (inChar == ')') {
61 c = MyComplex(inReal, inImag);
62 validInput = true;
63 }
64 }
65 }
66 if (!validInput) in.setstate(std::ios_base::failbit);
67 return in;
68 }
69
70 // Overloading + operator for c1 + c2
71 const MyComplex operator+ (const MyComplex & lhs, const MyComplex & rhs) {
72 MyComplex result(lhs);
73 result += rhs; // uses overload +=
74 return result;
12 of 17 22/03/2020, 19:45
Object-oriented Programming (OOP) in C++ https://www3.ntu.edu.sg/home/ehchua/programming/cpp/cp7_Operator...
Program Notes:
The prefix ++ increments the real part, and returns this object by reference. The pos�ix ++ saves this object, increments the real part, and returns the
saved object by value. Pos�ix opera�on is clearly less efficient than prefix opera�on!
The + operators use the += operator (for academic purpose).
The friend func�ons is allow to access the private data members.
The overloaded stream inser�on operator << outputs "(real,imag)".
The overloaded stream extrac�on operator >> inputs "(real,imag)". It sets the failbit of the istream object if the input is not valid.
TestMyComplex.cpp
1 /* Test Driver for MyComplex class (TestMyComplex.cpp) */
2 #include <iostream>
3 #include <iomanip>
4 #include "MyComplex.h"
5
6 int main() {
7 std::cout << std::fixed << std::setprecision(2);
8
9 MyComplex c1(3.1, 4.2);
10 std::cout << c1 << std::endl; // (3.10,4.20)
11 MyComplex c2(3.1);
12 std::cout << c2 << std::endl; // (3.10,0.00)
13
14 MyComplex c3 = c1 + c2;
15 std::cout << c3 << std::endl; // (6.20,4.20)
16 c3 = c1 + 2.1;
17 std::cout << c3 << std::endl; // (5.20,4.20)
18 c3 = 2.2 + c1;
19 std::cout << c3 << std::endl; // (5.30,4.20)
20
21 c3 += c1;
22 std::cout << c3 << std::endl; // (8.40,8.40)
23 c3 += 2.3;
24 std::cout << c3 << std::endl; // (10.70,8.40)
25
26 std::cout << ++c3 << std::endl; // (11.70,8.40)
27 std::cout << c3++ << std::endl; // (11.70,8.40)
28 std::cout << c3 << std::endl; // (12.70,8.40)
29
30 // c1+c2 = c3; // error: c1+c2 returns a const
31 // c1++++; // error: c1++ returns a const
32
33 // MyComplex c4 = 5.5; // error: implicit conversion disabled
34 MyComplex c4 = (MyComplex)5.5; // explicit type casting allowed
35 std::cout << c4 << std::endl; // (5.50,0.00)
36
37 MyComplex c5;
38 std::cout << "Enter a complex number in (real,imag): ";
39 std::cin >> c5;
40 if (std::cin.good()) { // if no error
41 std::cout << c5 << std::endl;
42 } else {
43 std::cerr << "Invalid input" << std::endl;
44 }
45 return 0;
46 }
13 of 17 22/03/2020, 19:45
Object-oriented Programming (OOP) in C++ https://www3.ntu.edu.sg/home/ehchua/programming/cpp/cp7_Operator...
MyDynamicArray.h
1 /*
2 * The MyDynamicArray class header (MyDynamicArray.h)
3 * A dynamic array of double elements
4 */
5 #ifndef MY_DYNAMIC_ARRAY_H
6 #define MY_DYNAMIC_ARRAY_H
7
8 #include <iostream>
9
10 class MyDynamicArray {
11 private:
12 int size_; // size of array
13 double * ptr; // pointer to the elements
14
15 public:
16 explicit MyDynamicArray (int n = 8); // Default constructor
17 explicit MyDynamicArray (const MyDynamicArray & a); // Copy constructor
18 MyDynamicArray (const double a[], int n); // Construct from double[]
19 ~MyDynamicArray(); // Destructor
20
21 const MyDynamicArray & operator= (const MyDynamicArray & rhs); // Assignment a1 = a2
22 bool operator== (const MyDynamicArray & rhs) const; // a1 == a2
23 bool operator!= (const MyDynamicArray & rhs) const; // a1 != a2
24
25 double operator[] (int index) const; // a[i]
26 double & operator[] (int index); // a[i] = x
27
28 int size() const { return size_; } // return size of array
29
30 // friends
31 friend std::ostream & operator<< (std::ostream & out, const MyDynamicArray & a); // out << a
32 friend std::istream & operator>> (std::istream & in, MyDynamicArray & a); // in >> a
33 };
34
35 #endif
Program Notes:
In C++, the you cannot use the same name for a data member and a member func�on. As I would like to have a public func�on called size(), which is
consistent with the C++ STL, I named the data member size_ with a trailing underscore, following C++'s best prac�ces. Take note that leading
underscore(s) are used by C++ compiler for its internal variables (e.g., _xxx for data members and __xxx for local variables).
As we will be dynamically alloca�ng memory in the constructor, we provide our own version of destructor, copy constructor and assignment operator to
manage the dynamically allocated memory. The defaults provided by the C++ compiler do not work on dynamic memory.
We provide 3 constructors: a default constructor with an op�onal size, a copy constructor to construct an instance by copying another instance, and a
construct to construct an instance by copying from a regular array.
We provide 2 version of indexing operators: one for read opera�on (e.g., a[i]) and another capable of write opera�on (e.g., a[i] = x). The read
version is declared as a const member func�on; whereas the write version return a reference to the element, which can be used as lvalue for assignment.
MyDynamicArray.cpp
1 /* The MyDynamicArray class implementation (MyDynamicArray.cpp) */
2 #include <stdexcept>
3 #include "MyDynamicArray.h"
4
5 // Default constructor
6 MyDynamicArray::MyDynamicArray (int n) {
7 if (n <= 0) {
8 throw std::invalid_argument("error: size must be greater then zero");
9 }
10
11 // Dynamic allocate memory for n elements
12 size_ = n;
13 ptr = new double[size_];
14 for (int i = 0; i < size_; ++i) {
14 of 17 22/03/2020, 19:45
Object-oriented Programming (OOP) in C++ https://www3.ntu.edu.sg/home/ehchua/programming/cpp/cp7_Operator...
15 of 17 22/03/2020, 19:45
Object-oriented Programming (OOP) in C++ https://www3.ntu.edu.sg/home/ehchua/programming/cpp/cp7_Operator...
91
92 // Overload stream insertion operator out << a (as friend)
93 std::ostream & operator<< (std::ostream & out, const MyDynamicArray & a) {
94 for (int i = 0; i < a.size_; ++i) {
95 out << a.ptr[i] << ' ';
96 }
97 return out;
98 }
99
100 // Overload stream extraction operator in >> a (as friend)
101 std::istream & operator>> (std::istream & in, MyDynamicArray & a) {
102 for (int i = 0; i < a.size_; ++i) {
103 in >> a.ptr[i];
104 }
105 return in;
106 }
Program Notes:
Constructor: [TODO]
Copy Constructor:
Assignment Operator:
Indexing Operator:
TestMyDynamicArray.cpp
1 /* Test Driver for MyDynamicArray class (TestMyDynamicArray.cpp) */
2 #include <iostream>
3 #include <iomanip>
4 #include "MyDynamicArray.h"
5
6 int main() {
7 std::cout << std::fixed << std::setprecision(1) << std::boolalpha;
8
9 MyDynamicArray a1(5);
10 std::cout << a1 << std::endl; // 0.0 0.0 0.0 0.0 0.0
11 std::cout << a1.size() << std::endl; // 5
12
13 double d[3] = {1.1, 2.2, 3.3};
14 MyDynamicArray a2(d, 3);
15 std::cout << a2 << std::endl; // 1.1 2.2 3.3
16
17 MyDynamicArray a3(a2); // Copy constructor
18 std::cout << a3 << std::endl; // 1.1 2.2 3.3
19
20 a1[2] = 8.8;
21 std::cout << a1[2] << std::endl; // 8.8
22 // std::cout << a1[22] << std::endl; // error: out_of_range
23
24 a3 = a1;
25 std::cout << a3 << std::endl; // 0.0 0.0 8.8 0.0 0.0
26
27 std::cout << (a1 == a3) << std::endl; // true
28 std::cout << (a1 == a2) << std::endl; // false
29
30 const int SIZE = 3;
31 MyDynamicArray a4(SIZE);
32 std::cout << "Enter " << SIZE << " elements: ";
33 std::cin >> a4;
34 if (std::cin.good()) {
35 std::cout << a4 << std::endl;
36 } else {
37 std::cerr << "Invalid input" << std::endl;
38 }
39 return 0;
40 }
16 of 17 22/03/2020, 19:45
Object-oriented Programming (OOP) in C++ https://www3.ntu.edu.sg/home/ehchua/programming/cpp/cp7_Operator...
Feedback, comments, corrections, and errata can be sent to Chua Hock-Chuan ([email protected]) | HOME
17 of 17 22/03/2020, 19:45