CHAPTER 15 OVERLOADING AND TEMPLATES In this chapter

  • Slides: 144
Download presentation
CHAPTER 15 OVERLOADING AND TEMPLATES

CHAPTER 15 OVERLOADING AND TEMPLATES

In this chapter, you will: · Learn about overloading · Become aware of the

In this chapter, you will: · Learn about overloading · Become aware of the restrictions on operator overloading · Examine the pointer this · Learn about friend functions · · Explore the members and nonmembers of a class Discover how to overload various operators Learn about templates Explore how to construct function templates and class templates

 • The capability of combining data and operations on data is called encapsulation.

• The capability of combining data and operations on data is called encapsulation. This is the first principle of OOD. • In Chapter 12, we also defined abstract data type (ADT) and discussed how classes in C++ implement ADT. • In Chapter 13, we discussed how new classes could be derived from existing classes through the mechanism of inheritance and composition. • Inheritance is the second principle of OOD, as defined in Chapter 13, and encourages code reuse.

WHY OPERATOR OVERLOADING IS NEEDED • Recall the class clock. Type as defined in

WHY OPERATOR OVERLOADING IS NEEDED • Recall the class clock. Type as defined in Chapter 12. • Consider the following statements. clock. Type my. Clock(8, 23, 34); clock. Type your. Clock(4, 5, 30); my. Clock. print. Time(); my. Clock. increment. Seconds(); if(my. Clock. equal. Time(your. Clock)). . .

 • We would like to use the following statements in place of the

• We would like to use the following statements in place of the above statements. cout<<my. Clock; my. Clock++; if(my. Clock == your. Clock). . .

 • The only built-in operations on classes are the assignment operator and the

• The only built-in operations on classes are the assignment operator and the member selection operator. • Therefore, other operators cannot be applied, directly, on class objects. • C++ allows the programmer to extend the definitions of most of the operators to work with classes • In C++’s terminology, this is called operator overloading.

OPERATOR OVERLOADING · C++ allows the user to overload most of the operators to

OPERATOR OVERLOADING · C++ allows the user to overload most of the operators to work effectively in a specific application. · C++ does not allow the user to create new operators. · Most of the existing operators can be overloaded to manipulate class objects. · In order to overload an operator we must write functions. · The name of the function that overloads an operator is the reserved word operator followed by the operator to be overloaded. · The following function name overloads >= operator>= · Operator function: The function that overloads an operator.

Syntax for Operator Functions The syntax of the heading of an operator function is

Syntax for Operator Functions The syntax of the heading of an operator function is return. Type operator. Symbol(arguments) · The operator function is a value-returning function. · In C++, operator is a reserved word. · To overload an operator for a class: 1. Include the function to overload the operator (that is, the operator function) in the definition of the class. 2. Write the definition of the operator function.

Overloading an Operator: Some Restrictions When overloading an operator the following should be kept

Overloading an Operator: Some Restrictions When overloading an operator the following should be kept in mind. 1. You cannot change the precedence of an operator. 2. The associativity cannot be changed. (For example, the associativity of the arithmetic operator addition is from left to right and it cannot be changed. ) 3. Default arguments cannot be used with an overloaded operator. 4. You cannot change the number of arguments that an operator takes. 5. You cannot create new operators. Only existing operators can be overloaded. The operators that cannot be overloaded are. . * : : ? : sizeof 6. The meaning of how an operator works with built-in types, such as int, remains the same. 7. Operators can be overloaded either for objects of the user-defined types, or for a combination of objects of the user-defined type and objects of the built-in type.

The following is a list of operators that can be overloaded. + ! >=

The following is a list of operators that can be overloaded. + ! >= |= ->* && != &= , * || += << -> / = -= >> [] % == *= >>= () ^ < /= <<= ~ & <= %= ++ new | > ^= -delete

this Pointer · Every object of a class maintains a (hidden) pointer to itself

this Pointer · Every object of a class maintains a (hidden) pointer to itself and the name of this pointer is this. · In C++, this is a reserved word. · When an object invokes a member function, the this pointer of the object is referenced by the member function. · Suppose that test is a class and it has a member function, say one. Further suppose that the definition of one looks like: test: : one() {. . . return *this; }

If x and y are objects of the type test, the statement y =

If x and y are objects of the type test, the statement y = x. one(); returns the value of the object x to object y, that is, the data members of x will be copied into the corresponding data members of y. · When the object x invokes the function one, the pointer this in the definition of the member function one refers to the object x and so this means the address of x and *this means the value of x.

Example 16 -1 class this. Pointer. Class { public: void set(int a, int b,

Example 16 -1 class this. Pointer. Class { public: void set(int a, int b, int c); void print() const; this. Pointer. Class update. XYZ(); //Post: x = 2 * x; y = y + 2; // z = z * z; this. Pointer. Class(int a = 0, int b = 0, int c = 0); private: int x; int y; int z; };

void this. Pointer. Class: : set(int a, int b, int c) { x =

void this. Pointer. Class: : set(int a, int b, int c) { x = a; y = b; z = z; } void this. Pointer. Class: : print() const { cout<<"x = "<<x <<", y = "<<y <<", z = "<<z<<endl; } this. Pointer. Class: : update. XYZ() { x = 2 * x; y = y + 2; z = z * z; return *this; }

this. Pointer. Class: : this. Pointer. Class(int a, int b, int c) { x

this. Pointer. Class: : this. Pointer. Class(int a, int b, int c) { x = a; y = b; z = c; }

int main() { this. Pointer. Class object 1(3, 5, 7); this. Pointer. Class object

int main() { this. Pointer. Class object 1(3, 5, 7); this. Pointer. Class object 2; //Line 1 //Line 2 cout<<"Object 1: "; object 1. print(); //Line 3 //Line 4 object 2 = object 1. update. XYZ(); //Line 5 cout<<"After updating object 1: "; object 1. print(); //Line 6 //Line 7 cout<<"Object 2: "; object 2. print(); //Line 8 //Line 9 return 0; } Output Object 1: x = 3, y = 5, z = 7 After updating object 1: x = 6, y = 7, z = 49 Object 2: x = 6, y = 7, z = 49

Example 16 -2 class person. Type { public: void print() const; void set. Name(string

Example 16 -2 class person. Type { public: void print() const; void set. Name(string first, string last); person. Type& set. Last. Name(string last); //Function to set the last name //Post: last. Name = last; //After setting the last name, a reference //to the object, that is, the address of the //object, is returned person. Type& set. First. Name(string first); //Function to set the first name //Post: first. Name = last; //After setting the first name, a reference //to the object, that is, the address of the //object, is returned void get. Name(string& first, string& last); person. Type(string first = "", string last = "");

private: string first. Name; //store the first name string last. Name; //store the last

private: string first. Name; //store the first name string last. Name; //store the last name }; person. Type& person. Type: : set. Last. Name(string last) { last. Name = last; return *this; } person. Type& person. Type: : set. First. Name(string first) { first. Name = first; return *this; }

int main() { person. Type student 1("Angela", "Clodfelter"); //Line 1 person. Type student 2;

int main() { person. Type student 1("Angela", "Clodfelter"); //Line 1 person. Type student 2; //Line 2 person. Type student 3; //Line 3 cout<<"Line 4 -- Student 1: "; student 1. print(); cout<<endl; //Line 4 //Line 5 //Line 6 student 2. set. First. Name("Shelly"). set. Last. Name("Malik"); //Line 7 cout<<"Line 8 -- Student 2: "; student 2. print(); cout<<endl; //Line 8 //Line 9 //Line 10 student 3. set. First. Name("Chelsea"); //Line 11 cout<<"Line 12 -- Student 3: "; student 3. print(); cout<<endl; //Line 12 //Line 13 //Line 14 student 3. set. Last. Name("Tomek"); //Line 15

cout<<"Line 16 -- Student 3: "; student 3. print); cout<<endl; return 0; } Output

cout<<"Line 16 -- Student 3: "; student 3. print); cout<<endl; return 0; } Output Line 4 -- Student 1: Angela Clodfelter 8 -- Student 2: Shelly Malik 12 -- Student 3: Chelsea 16 -- Student 3: Chelsea Tomek //Line 16 //Line 17 //Line 18

Friend Functions of Classes • A function that is defined outside the scope of

Friend Functions of Classes • A function that is defined outside the scope of a class is called a friend function. • A friend function is a nonmember function of the class, but has access to the private data members of the class. • To make a function friend to a class, the reserved word friend precedes the function prototype (in the class definition). • The word friend appears only in the function prototype (in the class definition), not in the definition of the friend function.

class. Illus. Friend { friend void two(. . . ); . . . };

class. Illus. Friend { friend void two(. . . ); . . . }; · In the definition of the class. Illus. Friend, two is declared as a friend of the class. Illus. Friend; that is, it is a nonmember function of the class. Illus. Friend. · When you write the definition of the function two, any object of the type class. Illus. Friend—which is either a local variable of two or a formal parameter of two—can access its private members within the definition of the function two. · Because a friend function is not a member of a class, its declaration can be placed within the private, protected, or public part of the class.

Definition of a friend Function · When writing the definition of the friend function,

Definition of a friend Function · When writing the definition of the friend function, the name of the class and the scope resolution operator does not precede the name of the friend function in the function heading. · The definition of the function two in the above class. Illus. Friend is: void two(. . . ) {. . . } · We will place the definition of the friend function in the implementation file.

Example 16 -3 class. Illus. Friend { friend void two(class. Illus. Friend c. LFObject);

Example 16 -3 class. Illus. Friend { friend void two(class. Illus. Friend c. LFObject); public: void print(); void setx(int a); private: int x; }; void class. Illus. Friend: : print() { cout<<"In class. Illus. Friend: x = "<<x<<endl; } void class. Illus. Friend: : setx(int a) { x = a; }

void two(class. Illus. Friend c. LFObject) { class. Illus. Friend local. Two. Object; //Line

void two(class. Illus. Friend c. LFObject) { class. Illus. Friend local. Two. Object; //Line 1 //Line 2 local. Two. Object. x = 45; //Line 3 local. Two. Object. print(); cout<<endl; //Line 4 //Line 5 c. LFObject. x = 88; //Line 7 c. LFObject. print(); cout<<endl; //Line 8 //Line 9 cout<<"Line 6: In Friend Function two accessing " <<"private data member x " <<local. Two. Object. x<<endl; //Line 6 } cout<<"Line 10: In Friend Function two accessing " <<"private data member x " <<local. Two. Object. x<<endl; //Line 10

int main() { class. Illus. Friend a. Object; a. Object. setx(32); //Line 11 //Line

int main() { class. Illus. Friend a. Object; a. Object. setx(32); //Line 11 //Line 12 cout<<"Line 13: a. Object. x: "; //Line 13 a. Object. print(); //Line 14 cout<<endl; //Line 15 cout<<"*~*~*~* Testing Friend Function " <<"two *~*~*~*"<<endl; //Line 16 two(a. Object); } return 0; //Line 17

Output Line 13: a. Object. x: In class. Illus. Friend: x = 32 *~*~*~*

Output Line 13: a. Object. x: In class. Illus. Friend: x = 32 *~*~*~* Testing Friend Function two *~*~*~* In class. Illus. Friend: x = 45 Line 6: In Friend Function two accessing private data member x 45 In class. Illus. Friend: x = 88 Line 10: In Friend Function two accessing private data member x 45

Operator Functions as Member Functions and Nonmember Functions 1. The function that overloads any

Operator Functions as Member Functions and Nonmember Functions 1. The function that overloads any of the operators (), [], ->, or = for a class must be declared as a member of the class. 2. Suppose an operator op is overloaded for a class, say Op. Over. Class. a. If the leftmost operand of op is an object of a different type (that is, not of the type Op. Over. Class), the function that overloads the operator op for Op. Over. Class must be a nonmember—that is, a friend of the class Op. Over. Class. b. If the operator function that overloads the operator op for the class Op. Over. Class is a member of the class Op. Over. Class, then when applying op on objects of the type Op. Over. Class, the leftmost operand of op must be of the type Op. Over. Class.

 • Except for some of the operators, as explained above, most of the

• Except for some of the operators, as explained above, most of the operators can be overloaded either as member functions or as nonmember functions. • The following class is used to illustrate operator overloading. class Op. Over. Class {. . . private: int a; int b; }; Op. Over. Class x; Op. Over. Class y; Op. Over. Class z; .

Binary Operators as Member Functions • Suppose that the binary operator + is overloaded

Binary Operators as Member Functions • Suppose that the binary operator + is overloaded for the class Op. Over. Class. Overloading + as a Member Function • Suppose that + is overloaded as a member function of the class Op. Over. Class. • The name of the function to overload + for the class Op. Over. Class is operator+

 • Since x and y are objects of the type Op. Over. Class,

• Since x and y are objects of the type Op. Over. Class, we can perform the operation x + y • The compiler translates this expression into the following expression: x. operator+(y) • In this expression, there is only one argument to the function operator+, which is y. • In the above statement, operator+ has direct access to the private members of the object x. • The first argument to operator+ is the object that is invoking the function operator+ and the second argument is passed as a parameter to this function.

 • Suppose that the operator + adds the corresponding data members of the

• Suppose that the operator + adds the corresponding data members of the objects. • The result of the expression x + y is an object of the type Op. Over. Class. • The return type of the operator function operator+ is of the type Op. Over. Class. • The function prototype of operator+ in the definition of the class Op. Over. Class is: Op. Over. Class operator+(const Op. Over. Class&) const;

Op. Over. Class: : operator+ (const Op. Over. Class& other. Object) const { Op.

Op. Over. Class: : operator+ (const Op. Over. Class& other. Object) const { Op. Over. Class temp; temp. a = a + other. Object. a; temp. b = b + other. Object. b; return temp; }

General Syntax to Overload Binary (Arithmetic) Operators as Member Functions Function Prototype (to be

General Syntax to Overload Binary (Arithmetic) Operators as Member Functions Function Prototype (to be included in the definition of the class): return. Type operator op(class. Name); • op stands for the binary operator to be overloaded. • return. Type is the type of the value returned by the function. • class. Name is the name of the class for which the operator is being overloaded.

Function Definition: return. Type class. Name: : operator op (const class. Name& other. Object)

Function Definition: return. Type class. Name: : operator op (const class. Name& other. Object) const { //algorithm to perform the operation return (value); }

Example 16 -4 class Op. Over. Class { public: void print() const; //Overload arithmetic

Example 16 -4 class Op. Over. Class { public: void print() const; //Overload arithmetic operators Op. Over. Class operator+(const Op. Over. Class&) const; Op. Over. Class operator*(const Op. Over. Class&) const; Op. Over. Class(int i = 0, int j = 0); private: int a; int b; }; void Op. Over. Class: : print() const { cout<<"("<<a<<", "<<b<<")"; }

Op. Over. Class: : Op. Over. Class(int i, int j) { a = i;

Op. Over. Class: : Op. Over. Class(int i, int j) { a = i; b = j; } Op. Over. Class: : operator+ (const Op. Over. Class& right) const { Op. Over. Class temp; temp. a = a + right. a; temp. b = b + right. b; return temp; } Op. Over. Class: : operator* (const Op. Over. Class& right) const { Op. Over. Class temp; temp. a = a * right. a; temp. b = b * right. b; return temp; }

int main() { Op. Over. Class cout<<"Line u. print(); cout<<endl; cout<<"Line v. print(); cout<<endl;

int main() { Op. Over. Class cout<<"Line u. print(); cout<<endl; cout<<"Line v. print(); cout<<endl; w 1 = u + v; cout<<"Line w 1. print(); cout<<endl; u(23, 45); //Line 1 v(12, 10); //Line 2 w 1; //Line 3 w 2; //Line 4 5: u = "; //Line 5 //Line 6; output u //Line 7 8: v = "; //Line 8 //Line 9; output v //Line 10 //Line 11; add u and v 12: w 1 = "; //Line 12 //Line 13; output w 1 //Line 14

w 2 = u * v; //Line 15; cout<<"Line 16: w 2 = ";

w 2 = u * v; //Line 15; cout<<"Line 16: w 2 = "; w 2. print(); cout<<endl; } return 0; Output Line 5: u = 8: v = 12: w 1 16: w 2 (23, 45) (12, 10) = (35, 55) = (276, 450) multiply u and v //Line 16 //Line 17; output w 2 //Line 18

Overloading Relational Operators as Member Functions • We overload the equality operator, ==, for

Overloading Relational Operators as Member Functions • We overload the equality operator, ==, for the class Op. Over. Class. • Since the result of a relational operator is either true or false, the return. Type of the function operator== is Boolean. • The syntax of the function prototype to be included in the definition of the class Op. Over. Class is: bool operator==(const Op. Over. Class&) const;

bool Op. Over. Class : : operator== (const Op. Over. Class& right) const {

bool Op. Over. Class : : operator== (const Op. Over. Class& right) const { return(a == right. a && b == right. b); }

General Syntax to Overload Binary Relational Operators as Member Functions Function Prototype bool operator

General Syntax to Overload Binary Relational Operators as Member Functions Function Prototype bool operator op(const class. Name&) const; • op is the relational operator that is being overloaded. • class. Name is the name of the class for the operator op is being overloaded. Function Definition: bool class. Name: : operator op(const class. Name& right) const { //Compare and return the value }

Binary Operators as Nonmember Functions • Suppose that + is overloaded as a nonmember

Binary Operators as Nonmember Functions • Suppose that + is overloaded as a nonmember function of the class Op. Over. Class. • Suppose that the following operation is to be performed. x + y • This expression is compiled as operator+(x, y) • The function operator+ has two arguments. • The function operator+ is neither a member of the object x nor a member of the object y. • The objects to be added are passed as arguments to the function operator+.

 • To include the operator function operator+ as a nonmember of the class

• To include the operator function operator+ as a nonmember of the class in the definition of the class the reserved word friend must appear before the function heading. • The function operator+ must have two arguments. • To include operator+ as a nonmember in the definition of the class Op. Over. Class its prototype in the definition of Op. Over. Class is friend Op. Over. Class operator+(const Op. Over. Class&, const Op. Over. Class&);

Op. Over. Class operator+( const Op. Over. Class& first. Object, const Op. Over. Class&

Op. Over. Class operator+( const Op. Over. Class& first. Object, const Op. Over. Class& second. Object) { Op. Over. Class temp; temp. a = first. Object. a + second. Object. a; temp. b = first. Object. b + second. Object. b; return temp; }

 • In the above definition, we add the corresponding data members of first.

• In the above definition, we add the corresponding data members of first. Object and second. Object and store the result in temp. • Recall that the private members of a class are local to the class and therefore cannot be accessed outside the class. • Following this rule, since operator+ is not a member of the class Op. Over. Class, in the definition of the function operator+, expressions such as first. Object. a must be illegal since a is a private member of first. Object. • Since operator+ was declared as a friend function of the class Op. Over. Class, an object of the type Op. Over. Class can access its private members in the definition of operator+. • In the function heading, the name of the class, that is, Op. Over. Class and the scope resolution operator is not included before the name of the function operator+ since the function operator+ is not a member of the class.

General Syntax to Overload Binary (Arithmetic) Operators as Nonmember Functions Function Prototype (to be

General Syntax to Overload Binary (Arithmetic) Operators as Nonmember Functions Function Prototype (to be included in the definition of the class): friend return. Type operator op(const class. Name&, const class. Name&); • op stands for the binary operator to be overloaded. • return. Type is the type of the value returned by the function. • class. Name is the name of the class for which the operator is being overloaded.

Function Definition return. Type operator op(const class. Name& first. Object, const class. Name& second.

Function Definition return. Type operator op(const class. Name& first. Object, const class. Name& second. Object) { //algorithm to perform the operation return (value); }

Overloading Relational Operators as Nonmember Functions • We overload the equality operator, ==, for

Overloading Relational Operators as Nonmember Functions • We overload the equality operator, ==, for the class Op. Over. Class. • The return type of the function operator== is Boolean. Function Prototype friend bool operator==(const Op. Over. Class&, const Op. Over. Class&);

Function Definition bool operator==(const Op. Over. Class& first. Object, const Op. Over. Class& second.

Function Definition bool operator==(const Op. Over. Class& first. Object, const Op. Over. Class& second. Object) { return(first. Object. a == second. Object. a && first. Object. b == second. Object. b); }

General Syntax to Overload Binary Relational Operators as Nonmember Functions Function Prototype (to be

General Syntax to Overload Binary Relational Operators as Nonmember Functions Function Prototype (to be included in the definition of the class): friend bool operator op(const class. Name&, const class. Name&); • op is the relational operator that is being overloaded. • class. Name is the name of the class for the operator op is being overloaded. Function Definition: bool operator op (const class. Name& first. Object, const class. Name& second. Object) { //Compare and return the value }

Overloading Stream Insertion (<<) and Extraction (>>) Operators • The operator function that overloads

Overloading Stream Insertion (<<) and Extraction (>>) Operators • The operator function that overloads the insertion operator << or the extraction operator >> for a class must be a nonmember of that class. Consider the following expression. cin>>x · In this expression, the left most operand of >>, that is, cin is an istream variable, not an object of the type Op. Over. Class. · Since the left most operand of >> is not an object of the type Op. Over. Class, the operator function that overloads the extraction operator for Op. Over. Class must be a nonmember of the class Op. Over. Class. · Similarly, the operator function that overloads the stream insertion operator for Op. Over. Class must be a nonmember function of Op. Over. Class.

Overloading the Stream Insertion Operator (<<) The general syntax to overload the stream insertion

Overloading the Stream Insertion Operator (<<) The general syntax to overload the stream insertion operator << for a class is: Function Prototype (to be included in the definition of the class): friend ostream& operator<<(ostream&, const class. Name& ); Function Definition: ostream& operator<<(ostream& os. Object, const class. Name& object) { //local declaration if any //Output members of the object //os. Object<<. . . //return stream object return os. Object; }

Overloading the Stream Extraction Operator (>>) The general syntax to overload the stream extraction

Overloading the Stream Extraction Operator (>>) The general syntax to overload the stream extraction operator >> for a class is: Function Prototype: friend istream& operator>>(istream&, class. Name&); Function Definition: istream& operator>>(istream& is. Object, class. Name& object) { //local declaration if any //Read data into the object //is. Object>>. . . //return stream object return is. Object; }

Example 16 -6 class Op. Over. Class { //overload stream insertion and extraction operators

Example 16 -6 class Op. Over. Class { //overload stream insertion and extraction operators friend ostream& operator<<(ostream&, const Op. Over. Class&); friend istream& operator>>(istream&, Op. Over. Class&); public: //overload arithmetic operators Op. Over. Class operator+(const Op. Over. Class&) const; Op. Over. Class operator*(const Op. Over. Class&) const; Op. Over. Class(int i = 0, int j = 0); private: int a; int b; };

//Definitions of the functions operator+, operator*, //and the constructor are the same as in

//Definitions of the functions operator+, operator*, //and the constructor are the same as in Example 16 -4 ostream& operator<<(ostream& os, const Op. Over. Class& right) { os<<"("<<right. a<<", "<<right. b<<")"; } return os; istream& operator>>(istream& is, Op. Over. Class& right) { is>>right. a>>right. b; } return is;

int main() { Op. Over. Class cout<<"Line cin>>v; cout<<endl; cout<<"Line return 0; } u(23,

int main() { Op. Over. Class cout<<"Line cin>>v; cout<<endl; cout<<"Line return 0; } u(23, 45); v; 3: u : "<<u<<endl; 4: Enter two integers: "; //Line //Line 7: v : "<<v<<endl; //Line 8: u + v : "<<u + v<<endl; //Line 9: u * v : "<<u * v<<endl; //Line 1 2 3 4 5 6 7 8 9

Sample Run: In this sample run, the user input is in red. Line 3:

Sample Run: In this sample run, the user input is in red. Line 3: u = (23, 45) Line 4: Enter two integers: 5 6 Line 7: v = (5, 6) Line 8: u + v = (28, 51) Line 9: u * v = (115, 270)

Overloading the Assignment Operator (=) General Syntax to Overload the Assignment Operator = for

Overloading the Assignment Operator (=) General Syntax to Overload the Assignment Operator = for a Class Function Prototype: const class. Name& operator=(const class. Name&);

Function Definition: const class. Name& class. Name: : operator= (const class. Name& right. Object)

Function Definition: const class. Name& class. Name: : operator= (const class. Name& right. Object) { //local declaration, if any if( this != &right. Object) { //avoid self-assignment //algorithm to copy the right. Object into this object } //return the object assigned return *this; }

· Suppose that the assignment operator, =, is overloaded for the class Op. Over.

· Suppose that the assignment operator, =, is overloaded for the class Op. Over. Class. · The statement x = y; is equivalent to the statement x. operator=(y); · Consider the statement x = y = z; · Because the associativity of the operator = is from right to left, this statement is equivalent to the statement x. operator=(y. operator=(z)); · We must first execute the expression y. operator=(z) //Line B

· The value returned by the expression y. operator=(z) will become the parameter to

· The value returned by the expression y. operator=(z) will become the parameter to the function operator= so as to assign a value to the object x. · Because the formal parameter to the function operator= is a reference parameter, the expression y. operator=(z) must return a reference to the object, rather than its value. · Now consider the statement x = x; · Here we are trying to copy the value of x into x; that is, this statement is a self-assignment. · We must prevent such statements because they waste computer time. · The body of the function operator= does prevent such assignments.

· Consider the if statement in the body of the operator function operator=: if(this

· Consider the if statement in the body of the operator function operator=: if(this != &right. Object) { //avoid self-assignment //algorithm to copy the right. Object into this object } · The statement x = x; is compiled into the statement x. operator=(x); · In the expression this != &right. Object this means the address of x, and &right. Object also means the address of x. Thus, the expression will evaluate to false and, the body of the if statement will be skipped.

Overloading Unary Operators 1. If the operator function is a member of the class,

Overloading Unary Operators 1. If the operator function is a member of the class, it has no parameters. 2. If the operator function is a nonmember, that is, a friend function of the class it has one parameter.

Overloading Increment (++) and Decrement (--) Operators • The increment operator has two forms,

Overloading Increment (++) and Decrement (--) Operators • The increment operator has two forms, pre-increment (++u) and post-increment (u++), where u is a variable, say of the type int. • In the case of pre-increment (++u), the value of the variable (u) is incremented by 1 before using the value of u in an expression and in the case of post-increment the value of u is used in the expression before it is incremented by 1. Pre-increment · To overload the pre-increment operator, in the function definition first we increment the value of the object and then use this pointer to return the value of the object.

Suppose that we overload the pre-increment operator for the class Op. Over. Class. Also

Suppose that we overload the pre-increment operator for the class Op. Over. Class. Also suppose that the operator function operator++ is a member of the class Op. Over. Class. Then the operator function operator++ has no arguments. Since the operator function operator++ has no arguments, we use this pointer to return the incremented value of the object. Op. Over. Class: : operator++() { //increment the object ++a; ++b; return *this; //return the incremented value of the object }

The General Syntax to Overload the Pre-increment Operator ++ As a Member Function Prototype

The General Syntax to Overload the Pre-increment Operator ++ As a Member Function Prototype (to be included in the definition of the class): class. Name operator++(); Function Definition: class. Name: : operator++() { //increment the value of the object by 1 return *this; }

· The operator function to overload the pre-increment operator can also be a nonmember

· The operator function to overload the pre-increment operator can also be a nonmember of the class Op. Over. Class operator++(Op. Over. Class& inc. Obj) { //increment the object (inc. Obj. a)++; (inc. Obj. b)++; return inc. Obj; //return the incremented value of the object }

General Syntax to Overload the Pre-increment Operator ++ as a Nonmember Function Prototype: friend

General Syntax to Overload the Pre-increment Operator ++ as a Nonmember Function Prototype: friend class. Name operator++(class. Name&); Function Definition: class. Name operator++(class. Name& inc. Obj) { //increment inc. Obj by 1 return inc. Obj; }

Overloading the Post-increment Operator · Overload the post-increment operator for the class Op. Over.

Overloading the Post-increment Operator · Overload the post-increment operator for the class Op. Over. Class. · In both cases, pre- and post-increment, the name of the operator function is the operator++. · To distinguish between pre- and post-increment operator overloading, we use a dummy parameter (of the type int) in the function heading of the operator function. · The function prototype for the post-increment operator for the class Op. Over. Class is Op. Over. Class operator++(int);

The statement x++; is compiled by the compiler in the statement x. operator++(0); and

The statement x++; is compiled by the compiler in the statement x. operator++(0); and so the function operator++ with a parameter executes. · The parameter 0 is used merely to distinguish between the pre- and postincrement operator functions. · The steps required to implement this function are: 1. Save the value of the object—say, in temp. 2. Increment the value of the object. 3. Return the value that was saved in temp.

· The function definition of the post-increment operator for the class Op. Over. Class

· The function definition of the post-increment operator for the class Op. Over. Class is Op. Over. Class: : operator++(int u) { Op. Over. Class temp = *this; //use this pointer to copy //the value of the object //increment the object a++; b++; } return temp; //return the old value of the object

The General Syntax to Overload the Post-increment Operator ++ as a Non Member Function

The General Syntax to Overload the Post-increment Operator ++ as a Non Member Function Prototype (to be included in the definition of the class): friend class. Name operator++(class. Name&, int); Function Definition: class. Name operator++(class. Name& inc. Obj, int u) { class. Name temp = inc. Obj; //copy inc. Obj into temp //increment inc. Obj return temp; //return the old value of the object }

//Definition of the class Op. Over. Class //The increment, decrement, arithmetic, and relational //operator

//Definition of the class Op. Over. Class //The increment, decrement, arithmetic, and relational //operator functions are members of the class Op. Over. Class { //overload the stream insertion and extraction operators friend ostream& operator<<(ostream&, const Op. Over. Class&); friend istream& operator>>(istream&, Op. Over. Class&); public: //overload the arithmetic operators Op. Over. Class operator+(const Op. Over. Class&) Op. Over. Class operator-(const Op. Over. Class&) Op. Over. Class operator*(const Op. Over. Class&) Op. Over. Class operator/(const Op. Over. Class&) const; //overload the increment and decrement operators Op. Over. Class operator++(); //pre-increment Op. Over. Class operator++(int); //post-increment Op. Over. Class operator--(); //pre-decrement Op. Over. Class operator--(int); //post-decrement

//overload the relational operators bool operator==(const Op. Over. Class&) const; bool operator!=(const Op. Over.

//overload the relational operators bool operator==(const Op. Over. Class&) const; bool operator!=(const Op. Over. Class&) const; bool operator<(const Op. Over. Class&) const; bool operator>=(const Op. Over. Class&) const; bool operator>(const Op. Over. Class&) const; //constructors Op. Over. Class(); Op. Over. Class(int i, int j); //include other functions as needed private: int a; int b; };

//Definition of the class Op. Over. Class //The increment, decrement, arithmetic, and relational //operator

//Definition of the class Op. Over. Class //The increment, decrement, arithmetic, and relational //operator functions are nonmembers of the class Op. Over. Class { //overload the stream insertion and extraction operators friend ostream& operator<<(ostream&, const Op. Over. Class&); friend istream& operator>>(istream&, Op. Over. Class&); friend //overload the arithmetic operators Op. Over. Class operator+(const Op. Over. Class&, const Op. Over. Class&); Op. Over. Class operator-(const Op. Over. Class&, const Op. Over. Class&); Op. Over. Class operator*(const Op. Over. Class&, const Op. Over. Class&); Op. Over. Class operator/(const Op. Over. Class&, const Op. Over. Class&); //overload the increment and decrement operators friend Op. Over. Class operator++(Op. Over. Class&); friend Op. Over. Class operator++(Op. Over. Class&, int); friend Op. Over. Class operator--(Op. Over. Class&, int);

friend friend //overload the relational operators bool operator==(const Op. Over. Class&, const Op. Over.

friend friend //overload the relational operators bool operator==(const Op. Over. Class&, const Op. Over. Class&); bool operator!=(const Op. Over. Class&, const Op. Over. Class&); bool operator<(const Op. Over. Class&, const Op. Over. Class&); bool operator>=(const Op. Over. Class&, const Op. Over. Class&); bool operator>(const Op. Over. Class&, const Op. Over. Class&); public: //constructors Op. Over. Class(); Op. Over. Class(int i, int j); //include other functions as needed private: int a; int b; };

Operator Overloading: Member Versus Nonmember · Certain operators must be overloaded as member functions

Operator Overloading: Member Versus Nonmember · Certain operators must be overloaded as member functions of the class, and some must be overloaded as nonmember (friend) functions. · The binary arithmetic operator + can be overloaded as a member function or a nonmember function. · If you overload + as a member function, then the operator + has direct access to the data members of one of the objects, and you need to pass only one object as a parameter. · If you overload + as a nonmember function, then you must pass both objects as parameters. · Overloading + as a nonmember could require additional memory and computer time to make a local copy of the data. · For efficiency purposes, wherever possible, you should overload operators as member functions.

· Classes and Pointer Data Members (Revisited) 1. Explicitly overload the assignment operator 2.

· Classes and Pointer Data Members (Revisited) 1. Explicitly overload the assignment operator 2. Include the copy constructor 3. Include the destructor · Operator Overloading: One Final Word

PROGRAMMING EXAMPLE: CLOCKTYPE · Chapter 12 defined a class clock. Type to implement the

PROGRAMMING EXAMPLE: CLOCKTYPE · Chapter 12 defined a class clock. Type to implement the time of day in a program. · We implemented the operations print time, increment time, and compare two times for equality using functions. · This example redefines the class clock. Type. · It also overloads the stream insertion and extraction operators for easy input and output, relational operators for comparisons, and the increment operator to increment the time by one second. · The program that uses the class clock. Type requires the user to input the time in the form hr: min: sec.

//Header file new. Clock. h #ifndef H_new. Clock #define H_new. Clock class clock. Type

//Header file new. Clock. h #ifndef H_new. Clock #define H_new. Clock class clock. Type { friend ostream& operator<< (ostream&, const clock. Type&); friend istream& operator>> (istream&, clock. Type&); public: void set. Time(int hours, int minutes, int seconds); //Function to set the private data members //hr, min, and sec //Post: hr = hours; min = minutes; sec = seconds void get. Time(int& hours, int& minutes, int& seconds); //Function to return the time //Post: hours = hr; minutes = min; seconds = sec; clock. Type operator++(); //Overload the pre-increment operator //Post: Time is incremented by one second

bool operator==(const clock. Type& other. Clock) const; //Overload the equality operator //Function returns true

bool operator==(const clock. Type& other. Clock) const; //Overload the equality operator //Function returns true if the time is equal //to other. Time, otherwise it returns the value false bool operator<=(const clock. Type& other. Clock) const; //Overload the less than or equal to operator //Function returns true if the time is less //than or equal to other. Time, otherwise it returns //the value false clock. Type(int hours = 0, int minutes = 0, int seconds = 0); //Constructor to initialize the object with the //values specified by the user. If no values are // specified, default values are assumed. //Post: hr = hours; min = minutes; sec = seconds private: int hr; //variable to store the hours int min; //variable to store the minutes int sec; //variable to store the seconds };

//overload the preincrement operator clock. Type: : operator++() { sec++; //Step a if(sec >

//overload the preincrement operator clock. Type: : operator++() { sec++; //Step a if(sec > 59) //Step b { sec = 0; //Step b. 1 min++; //Step b. 2 if(min > 59) { min = 0; hr++; if(hr > 23) hr = 0; } } } return *this; //Step b. 3. 1 //Step b. 3. 2 //Step b. 3. 3. 1 //Step c

//overload the equality operator bool clock. Type: : operator== (const clock. Type& other. Clock)

//overload the equality operator bool clock. Type: : operator== (const clock. Type& other. Clock) const { return(hr == other. Clock. hr && min == other. Clock. min && sec == other. Clock. sec); } //overload the less than or equal to operator bool clock. Type: : operator<= (const clock. Type& other. Clock) const { return((hr < other. Clock. hr) || (hr == other. Clock. hr && min < other. Clock. min) || (hr == other. Clock. hr && min == other. Clock. min && sec <= other. Clock. sec)); }

//constructor with parameters clock. Type: : clock. Type(int hours, int minutes, int seconds) {

//constructor with parameters clock. Type: : clock. Type(int hours, int minutes, int seconds) { if(0 <= hours && hours < 24) hr = hours; else hr = 0; if(0 <= minutes && minutes < 60) min = minutes; else min = 0; if(0 <= seconds && seconds < 60) sec = seconds; else sec = 0; }

void clock. Type: : set. Time(int hours, int minutes, int seconds) { if(0 <=

void clock. Type: : set. Time(int hours, int minutes, int seconds) { if(0 <= hours && hours < 24) hr = hours; else hr = 0; if(0 <= minutes && minutes < 60) min = minutes; else min = 0; } if(0 <= seconds && seconds < 60) sec = seconds; else sec = 0;

void clock. Type: : get. Time(int& hours, int& minutes, int& seconds) { hours =

void clock. Type: : get. Time(int& hours, int& minutes, int& seconds) { hours = hr; minutes = min; seconds = sec; }

The time must be output in the form hh: mm: ss //overload the stream

The time must be output in the form hh: mm: ss //overload the stream insertion operator ostream& operator<< (ostream& os. Object, const clock. Type& time. Out) { if(time. Out. hr < 10) os. Object<<'0'; os. Object<<time. Out. hr<<': '; if(time. Out. min < 10) os. Object<<'0'; os. Object<<time. Out. min<<': '; if(time. Out. sec < 10) os. Object<<'0'; os. Object<<time. Out. sec; } return os. Object; //return the ostream object

The input to the program is of the form hh: mm: ss //overload the

The input to the program is of the form hh: mm: ss //overload the stream extraction operator istream& operator>> (istream& is. Object, clock. Type& time. In) { char ch; is. Object>>time. In. hr; //Step a is. Object. get(ch); //Step b; read and discard : is. Object>>time. In. min; //Step c is. Object. get(ch); //Step d; read and discard : is. Object>>time. In. sec; //Step e return is. Object; } //Step f

//Program that uses the class clock. Type #include <iostream> #include "new. Clock. h" using

//Program that uses the class clock. Type #include <iostream> #include "new. Clock. h" using namespace std; int main() { clock. Type my. Clock(5, 6, 23); clock. Type your. Clock; //Line 1 //Line 2 cout<<"Line 3: my. Clock = "<<my. Clock<<endl; //Line 3 cout<<"Line 4: your. Clock = "<<your. Clock<<endl; //Line 4 cout<<"Line 5: Enter time in the form " <<"hr: min: sec "; //Line 5 cin>>my. Clock; //Line 6 cout<<"Line 7: The new time of my. Clock = " <<my. Clock<<endl; //Line 7 ++my. Clock; //Line 8 cout<<"Line 9: After increment the time, my. Clock = " <<my. Clock<<endl; //Line 9

your. Clock. set. Time(13, 35, 38); //Line 10 cout<<"Line 11: After setting the time,

your. Clock. set. Time(13, 35, 38); //Line 10 cout<<"Line 11: After setting the time, your. Clock = " <<your. Clock<<endl; //Line 11 if(my. Clock == your. Clock) //Line 12 cout<<"Line 13: The times of my. Clock and " <<"your. Clock are equal"<<endl; //Line 13 else //Line 14 cout<<"Line 15: The times of my. Clock and " <<"your. Clock are not equal"<<endl; //Line 15 if(my. Clock <= your. Clock) //Line 16 cout<<"Line 17: The time of my. Clock is less " <<"than or equal to "<<endl <<"the time of your. Clock"<<endl; //Line 17 else //Line 18 cout<<"Line 19: The time of my. Clock is " <<"greaterthan the time of your. Clock" <<endl; //Line 19 } return 0;

Sample Run In this sample run, the user input is in red. Line 3:

Sample Run In this sample run, the user input is in red. Line 3: my. Clock = 05: 06: 23 Line 4: your. Clock = 00: 00 Line 5: Enter the time in the form hr: min: sec 4: 50: 59 Line 7: The new time of my. Clock = 04: 50: 59 Line 9: After increment the time, my. Clock = 04: 51: 00 Line 11: After setting the time, your. Clock = 13: 35: 38 Line 15: The times of my. Clock and your. Clock are not equal Line 17: The time of my. Clock is less than or equal to the time of your. Clock

PROGRAMMING EXAMPLE: COMPLEX NUMBERS A number of the form a + ib, where i

PROGRAMMING EXAMPLE: COMPLEX NUMBERS A number of the form a + ib, where i 2 = -1, and a and b are real numbers, is called a complex number. We call a the real part and b the imaginary part of a + ib. Complex numbers can also be represented as ordered pairs (a, b). The addition and multiplication of complex numbers is defined by the following rules: (a + ib) + (c + id) = (a + c) + i(b + d) (a + ib) * (c + id) = (ac - bd) + i(ad + bc) Using the ordered pair notation (a + ib) + (c + id) = (a + c) + i(b + d) (a + ib) * (c + id) = (ac - bd) + i(ad + bc)

//Specification file complex. Type. h #ifndef H_complex. Number #define H_complex. Number class complex. Type

//Specification file complex. Type. h #ifndef H_complex. Number #define H_complex. Number class complex. Type { friend ostream& operator<< (ostream&, const complex. Type&); friend istream& operator>> (istream&, complex. Type&); public: void set. Complex(const double& real, const double& imag); complex. Type(double real = 0, double imag = 0); complex. Type operator+(const complex. Type& other. Complex) const; complex. Type operator*(const complex. Type& other. Complex) const; bool operator==(const complex. Type& other. Complex) const; private: double real. Part; double imaginary. Part; }; #endif

To output the complex number in the form (a, b) where a is the

To output the complex number in the form (a, b) where a is the real part and b is the imaginary part ostream& operator<<(ostream& os. Object, const complex. Type& complex) { os. Object<<"("; //Step os. Object<<complex. real. Part; //Step b os. Object<<", "; //Step os. Object<<complex. imaginary. Part; //Step os. Object<<")"; //Step a c d e return os. Object; //Return the ostream object }

Now the input is of the form, say (3, 5) istream& operator>> (istream& is.

Now the input is of the form, say (3, 5) istream& operator>> (istream& is. Object, complex. Type& complex) { char ch; is. Object>>complex. real. Part; is. Object>>ch; is. Object>>complex. imaginary. Part; is. Object>>ch; //Step //Step a b c d e return is. Object; //Return the istream object }

bool complex. Type: : operator==(const complex. Type& other. Complex) const { return(real. Part ==

bool complex. Type: : operator==(const complex. Type& other. Complex) const { return(real. Part == other. Complex. real. Part && imaginary. Part == other. Complex. imaginary. Part); } //constructor complex. Type: : complex. Type(double real, double imag) { real. Part = real; imaginary. Part = imag; } void complex. Type: : set. Complex(const double& real, const double& imag) { real. Part = real; imaginary. Part = imag; }

//overload the operator + complex. Type: : operator+ (const complex. Type& other. Complex) const

//overload the operator + complex. Type: : operator+ (const complex. Type& other. Complex) const { complex. Type temp; temp. real. Part = real. Part + other. Complex. real. Part; temp. imaginary. Part = imaginary. Part + other. Complex. imaginary. Part; return temp; }

//overload the operator * complex. Type: : operator* (const complex. Type& other. Complex) const

//overload the operator * complex. Type: : operator* (const complex. Type& other. Complex) const { complex. Type temp; temp. real. Part = (real. Part * other. Complex. real. Part) (imaginary. Part * other. Complex. imaginary. Part); temp. imaginary. Part = (real. Part * other. Complex. imaginary. Part) + (imaginary. Part * other. Complex. real. Part); return temp; }

//Program that uses the class complex. Type #include <iostream> #include "complex. Type. h" using

//Program that uses the class complex. Type #include <iostream> #include "complex. Type. h" using namespace std; int main() { complex. Type num 1(23, 34); complex. Type num 2; complex. Type num 3; cout<<"Line 4: Num 1 = "<<num 1<<endl; cout<<"Line 5: Num 2 = "<<num 2<<endl; //Line 1 //Line 2 //Line 3 //Line 4 //Line 5 cout<<"Line 6: Enter the complex number " <<"in the form (a, b) "; //Line 6 cin>>num 2; //Line 7 cout<<endl; //Line 8

cout<<"Line 9: New value of num 2 = " <<num 2<<endl; //Line 9 num

cout<<"Line 9: New value of num 2 = " <<num 2<<endl; //Line 9 num 3 = num 1 + num 2; //Line 10 cout<<"Line 11: Num 3 = "<<num 3<<endl; //Line 11 cout<<"Line 12: "<<num 1<<" + "<<num 2 <<" = "<<num 1 + num 2<<endl; //Line 12 cout<<"Line 13: "<<num 1<<" * "<<num 2 <<" = "<<num 1 * num 2<<endl; //Line 13 return 0; }

Sample Run: In this sample run, the user input is in red. Line 4:

Sample Run: In this sample run, the user input is in red. Line 4: Num 1 = (23, 34) Line 5: Num 2 = (0, 0) Line 6: Enter the complex number in the form (a, b) (3, 4) Line 9: New value of num 2 = (3, 4) 11: Num 3 = (26, 38) 12: (23, 34) + (3, 4) = (26, 38) 13: (23, 34) * (3, 4) = (-67, 194)

OVERLOADING THE ARRAY INDEX (SUBSCRIPT) OPERATOR ([]) · The function to overload the operator

OVERLOADING THE ARRAY INDEX (SUBSCRIPT) OPERATOR ([]) · The function to overload the operator [] for a class must be a member of the class. · Since an array can be declared as constant or non-constant, we need to overload the operator [] to handle both the cases. · The syntax to declare the operator function operator[] as a member of a class for non-constant arrays is: Type& operator[](int index); · The syntax to declare the operator function operator[] as a member of a class for constant arrays is: const Type& operator[](int index) const; where Type is the data type of the array elements.

 • Suppose class. Test is a class that has an array data member.

• Suppose class. Test is a class that has an array data member. The definition of class. Test to overload the operator function operator [] is: class. Test { public: Type& operator[](int index); //overload the operator for nonconstant arrays const Type& operator[](int index) const; //overload the operator for constant arrays. . . private: Type *list; //pointer to the array int array. Size; }; where Type is the data type of the array elements.

//overload the operator [] for nonconstant arrays Type& class. Test: : operator[](int index) {

//overload the operator [] for nonconstant arrays Type& class. Test: : operator[](int index) { assert(0 <= index && index < array. Size); return(list[index]); //return a pointer of the //array component } //overload the operator [] for constant arrays const Type& class. Test: : operator[](int index) const { assert(0 <= index && index < array. Size); return(list[index]); //return a pointer of the //array component }

class. Test list 1; class. Test list 2; const class. Test list 3; ·

class. Test list 1; class. Test list 2; const class. Test list 3; · In the case of the statement list 1[2] = list 2[3]; the body of the operator function operator[] for nonconstant arrays is executed. · In the case of the statement list 1[2] = list 3[5]; first the body of the operator function operator[] for constant arrays is executed because list 3 is a constant array. Next, the body of the operator function operator[] for nonconstant arrays is executed to complete the execution of the assignment statement.

PROGRAMMING EXAMPLE: new. String · Recall that 1. A C string is a sequence

PROGRAMMING EXAMPLE: new. String · Recall that 1. A C string is a sequence of one or more characters, 2. C strings are enclosed in double quote marks, 3. C strings are null terminated, and 4. C strings stored in character arrays. · In this example, by a string we mean a C string. · The only allowable aggregate operations on strings are input and output. · To use other operations, the programmer need to include the header file cstring, which contains the specification of many functions for string manipulation. · We define a class for string manipulation and at the same time to further illustrate operator overloading.

//Header file my. String. h #ifndef H_my. String #define H_my. String #include <iostream> using

//Header file my. String. h #ifndef H_my. String #define H_my. String #include <iostream> using namespace std; class new. String { //overload the stream insertion and extraction operators friend ostream& operator<<(ostream&, const new. String&); friend istream& operator>>(istream&, new. String&); public: const new. String& operator=(const new. String&); //overload the assignment operator new. String(const char *); //constructor; conversion from the char string new. String(); //default constructor to initialize the string to null new. String(const new. String&); //copy constructor

~new. String(); //destructor char &operator[] (int); const char &operator[](int) const; //overload the relational operators

~new. String(); //destructor char &operator[] (int); const char &operator[](int) const; //overload the relational operators bool operator==(const new. String&) const; bool operator!=(const new. String&) const; bool operator<(const new. String&) const; bool operator>=(const new. String&) const; bool operator>(const new. String&) const; private: char *str. Ptr; //pointer to the char array //that holds the string int str. Length; //data member to store the length //of the string }; #endif

//Implementation file my. String. cpp #include <iostream> #include <iomanip> #include <cstring> #include <cassert> #include

//Implementation file my. String. cpp #include <iostream> #include <iomanip> #include <cstring> #include <cassert> #include "my. String. h" using namespace std;

//constructor: conversion from the char string to new. String: : new. String(const char *str)

//constructor: conversion from the char string to new. String: : new. String(const char *str) { str. Length = strlen(str); str. Ptr = new char[str. Length+1]; //allocate //memory to store the char string assert(str. Ptr != NULL); strcpy(str. Ptr, str); //copy string into str. Ptr } //default constructor to store the null string new. String: : new. String() { str. Length = 1; str. Ptr = new char[1]; assert(str. Ptr != NULL); strcpy(str. Ptr, ""); }

//copy constructor new. String: : new. String(const new. String& right. Str) { str. Length

//copy constructor new. String: : new. String(const new. String& right. Str) { str. Length = right. Str. str. Length; str. Ptr = new char[str. Length + 1]; assert(str. Ptr != NULL); strcpy(str. Ptr, right. Str. str. Ptr); } new. String: : ~new. String() { delete [] str. Ptr; } //destructor

//overload the assignment operator const new. String& new. String: : operator= (const new. String&

//overload the assignment operator const new. String& new. String: : operator= (const new. String& right. Str) { if(this != &right. Str) //avoid self-copy { delete [] str. Ptr; str. Length = right. Str. str. Length; str. Ptr = new char[str. Length + 1]; assert(str. Ptr != NULL); strcpy(str. Ptr, right. Str. str. Ptr); } return *this; } char& new. String: : operator[] (int index) { assert(0 <= index && index < str. Length); return str. Ptr[index]; }

const char& new. String: : operator[](int index) const { assert(0 <= index && index

const char& new. String: : operator[](int index) const { assert(0 <= index && index < str. Length); return str. Ptr[index]; } //overload the relational operators bool new. String: : operator== (const new. String& right. Str) const { return(strcmp(str. Ptr, right. Str. str. Ptr) == 0); } bool new. String: : operator<(const new. String& right. Str) const { return(strcmp(str. Ptr, right. Str. str. Ptr) < 0); } bool new. String: : operator<=(const new. String& right. Str) const { return(strcmp(str. Ptr, right. Str. str. Ptr) <= 0); }

bool new. String: : operator>(const new. String& right. Str) const { return(strcmp(str. Ptr, right.

bool new. String: : operator>(const new. String& right. Str) const { return(strcmp(str. Ptr, right. Str. str. Ptr) > 0); } bool new. String: : operator>=(const new. String& right. Str) const { return(strcmp(str. Ptr, right. Str. str. Ptr) >= 0); } bool new. String: : operator!=(const new. String& right. Str) const { return(strcmp(str. Ptr, right. Str. str. Ptr) != 0); }

//overload the stream insertion operator << ostream& operator<<(ostream& os. Object, const new. String& str)

//overload the stream insertion operator << ostream& operator<<(ostream& os. Object, const new. String& str) { os. Object<<str. Ptr; return os. Object; } //overload the stream extraction operator >> istream& operator>>(istream& is. Object, new. String& str) { char temp[81]; is. Object>>setw(81)>>temp; str = temp; } return is. Object;

 • The conversion constructor is a single parameter function and converts its argument

• The conversion constructor is a single parameter function and converts its argument to the object of constructor’s class. In this example, the conversion constructor is used to convert a string to an object of the new. String type. • Note that the assignment operator is explicitly overloaded only for objects of new. String type. However, the overloaded assignment operator also works if we want to store a character string into a new. String object.

Consider the declaration new. String str; and the statement str = "Hello there"; The

Consider the declaration new. String str; and the statement str = "Hello there"; The compiler translates this statement into the statement str. operator=("Hello there"); Now, 1. First the compiler automatically invokes the conversion constructor to create an object of new. String type to temporarily store the string "Hello there". 2. Second the compiler invokes the overloaded assignment operator to assign the temporary new. String object to object str.

//Test Program #include <iostream> #include <cstring> #include "my. String. h" using namespace std; int

//Test Program #include <iostream> #include <cstring> #include "my. String. h" using namespace std; int main() { new. String s 1 = "Sunny"; //initialize s 1 using //the assignment operator const new. String s 2("Warm"); //initialize s 2 using //the conversion constructor new. String s 3; //initialize s 3 to null new. String s 4; //initialize s 4 to null cout<<"Line 1: "<<s 1<<" <<s 3 <<"###. "<<endl; "<<s 2<<" ***" //Line 1 if(s 1 <= s 2) //compare s 1 and s 2; Line 2 cout<<"Line 3: "<<s 1<<" is less than "<<s 2 <<endl; //Line 3 else //Line 4 cout<<"Line 5: "<<s 2<<" is less than "<<s 1 <<endl; //Line 5

cout<<"Line 6: Enter a string of length " <<"at least 7 --> "; //Line

cout<<"Line 6: Enter a string of length " <<"at least 7 --> "; //Line 6 cin>>s 1; //input s 1; Line 7 cout<<endl<<"Line 8: New value of s 1 = "<<s 1 <<endl; //Line 8 s 4 = s 3 = "Birth Day"; //Line 9 cout<<"Line 10: s 3 = "<<s 3<<", s 4 = "<<s 4<<endl; //Line 10 s 3 = s 1; //Line 11 cout<<"Line 12: The new value of s 3 = "<<s 3<<endl; //Line 12 s 1 = "Bright Sky"; //Line 13 s 3[1] = s 1[5]; //Line 14 cout<<"Line 15: After replacing the second character of s 3 = " <<s 3<<endl; s 3[2] = s 2[3]; //Line 15 //Line 16 cout<<"Line 17: After replacing the third character of s 3 = " <<s 3<<endl; s 3[5] = 'g'; //Line 17 //Line 18 cout<<"Line 19: After replacing the sixth character of s 3 = " <<s 3<<endl; return 0; } //Line 19

Sample Run: In this sample run, the user input is in red. Line 1:

Sample Run: In this sample run, the user input is in red. Line 1: Hello Happy ***###. Line 5: Sunny is less than Warm Line 6: Enter a string of length at least 7 --> 123456789 Line 8: New value of s 1 = 123456789 Line 10: s 3 = Birth Day, s 4 = Birth Day Line 12: The new value of s 3 = 123456789 Line 15: After replacing the second character of str 3 = 1 t 3456789 Line 17: After replacing the third character of str 3 = 1 t. W 456789 Line 19: After replacing the sixth character of str 3 = 1 t. W 45 g 789

FUNCTION OVERLOADING • Overloading a function refers to several functions with the same name,

FUNCTION OVERLOADING • Overloading a function refers to several functions with the same name, but different parameters. The types of parameters determine which function to be executed. int larger. Int (int x, int y); char larger. Char(char first, char second); double larger. Float(double u, double v); new. String larger. String(new. String first, new. String second);

int larger(int x, int y); char larger(char first, char second); double larger(double u, double

int larger(int x, int y); char larger(char first, char second); double larger(double u, double v); new. String larger(new. String first, new. String second); · Function overloading is used when we have the same action for different sets of data. However, for function overloading to work, we must give the definition of each of the functions.

TEMPLATES · By using templates we write a single code for a set of

TEMPLATES · By using templates we write a single code for a set of related functions - called function template and related classes- called class template. The syntax for templates is: template <class Type> declaration; where Type is the type of the data and declaration is either a function declaration or a class declaration. · In C++, template is a reserved word. · The word class in the heading refers to any user-defined type or built in type. · Type is referred as a formal parameter to the template. · Just as variables are parameters to functions, types (that is, data types) are parameters to templates.

Function Templates • The syntax for function template is template <class Type> function definition;

Function Templates • The syntax for function template is template <class Type> function definition; where Type is referred to as a formal parameter of the template and it is used to specify the type of the parameters to the function and the return type of the function, and to declare variables within the function.

template <class Type> Type larger(Type x, Type y) { if(x >= y) return x;

template <class Type> Type larger(Type x, Type y) { if(x >= y) return x; else return y; } · The statement cout<<larger(5, 6)<<endl; is a call to the function template larger. · Since 5 and 6 are of the type int, data type int is substituted for Type and the compiler generates the appropriate code. · In the function template definition if we omit the body of the function, the function template then, as usual, is the prototype.

Example 16 -8 #include <iostream> #include "my. String. h" using namespace std; template <class

Example 16 -8 #include <iostream> #include "my. String. h" using namespace std; template <class Type> Type larger(Type x, Type y); int main() { cout<<"Line 1: Larger of 5 and 6 = " <<larger(5, 6)<<endl; //Line cout<<"Line 2: Larger of A and B = " <<larger('A', 'B')<<endl; //Line cout<<"Line 3: Larger of 5. 6 and 3. 2 = " <<larger(5. 6, 3. 2)<<endl; //Line new. String str 1 = "Hello"; //Line new. String str 2 = "Happy"; //Line cout<<"Line 6: Larger of "<<str 1<<" and " <<str 2<<" = "<<larger(str 1, str 2) <<endl; //Line return 0; } 1 2 3 4 5 6

template<class Type> Type larger(Type x, Type y) { if(x >= y) return x; else

template<class Type> Type larger(Type x, Type y) { if(x >= y) return x; else return y; } Output Line 1: Line 2: Line 3: Line 6: Larger of of 5 and 6 = 6 A and B = B 5. 6 and 3. 2 = 5. 6 Hello and Happy = Hello

Class Templates · Like function templates, class templates are used to write a single

Class Templates · Like function templates, class templates are used to write a single code segment for a set of related classes. Syntax: template<class Type> class declaration · Class templates are called parameterized types since based on the parameter type a specific class is generated.

template <class elem. Type> class list. Type { public: bool is. Empty(); bool is.

template <class elem. Type> class list. Type { public: bool is. Empty(); bool is. Full(); void search(const elem. Type& search. Item, bool& found); void insert(const elem. Type& new. Element); void remove(const elem. Type& remove. Element); void destroy. List(); void print. List(); list. Type(); private: elem. Type list[100]; //array to hold the list elements int length; //variable to store the number of //elements in the list };

· The statement list. Type<int> int. List; //Line 1 declares int. List to be

· The statement list. Type<int> int. List; //Line 1 declares int. List to be a list of 100 components and each component is of the type int. · The statement list. Type<new. String> string. List; //Line 2 component is of the type new. String. · In the statements in Lines 1 and 2, list. Type<int> and list. Type<new. String> are referred to as template instantiations or instantiations of the class template list. Type<elem. Type>, where elem. Type is the class parameter in the template header.

· A template instantiation can be created with either a built-in or userdefined type.

· A template instantiation can be created with either a built-in or userdefined type. · The function members of a class template are considered function templates.

The definition of the member insert of the class list. Type is template<class Type>

The definition of the member insert of the class list. Type is template<class Type> void list. Type<Type>: : insert(Type new. Element) {. . . } • In the heading of the member function’s definition the name of the class is specified with the parameter Type.

Header File and Implementation File of a Class Template · Until now, we have

Header File and Implementation File of a Class Template · Until now, we have placed the definition of the class and the definition of the member functions in separate files. · The object code was generated from the implementation file and linked with the user code. · Passing parameters to a function has an effect at run time, whereas passing a parameter to a class template has an effect at compile time. · Because the actual parameter to a class is specified in the client code, and because the compiler cannot instantiate a function template without the actual parameter to the template, we can no longer compile the implementation file independently of the client code. · We could put the class definition and the definitions of the function templates directly in the client code, or we could put the class definition and the definitions of the function templates together in the same header file. · Another alternative is to put the class definition and the definitions of the functions in separate files, but include a directive to the implementation file at the end of the header file. In either case, the function definitions and the client code are compiled together. · We will put the class definition and the function definitions in the same header file.

Example 16 -9 //Header file list. Type. h #ifndef H_list. Type #define H_list. Type

Example 16 -9 //Header file list. Type. h #ifndef H_list. Type #define H_list. Type #include <iostream> #include <cassert> using namespace std; template <class elem. Type> class list. Type { public: bool is. Empty(); bool is. Full(); int get. Length(); int get. Max. Size(); void sort(); void print() const; void insert. At(const elem. Type& item, int position); list. Type(int list. Size = 50); ~list. Type();

private: int max. Size; //maximum number that can be //stored in the list int

private: int max. Size; //maximum number that can be //stored in the list int length; //number of elements in the list elem. Type *list; //pointer to the array that //holds the list elements }; template<class elem. Type> bool list. Type<elem. Type>: : is. Empty() { return (length == 0) } template<class elem. Type> bool list. Type<elem. Type>: : is. Full() { return (length == max. Size); }

template<class elem. Type> int list. Type<elem. Type>: : get. Length() { return length; }

template<class elem. Type> int list. Type<elem. Type>: : get. Length() { return length; } template<class elem. Type> int list. Type<elem. Type>: : get. Max. Size() { return max. Size; } //constructor; the default array size is 50 template<class elem. Type> list. Type<elem. Type>: : list. Type(int list. Size) { max. Size = list. Size; length = 0; list = new elem. Type[max. Size]; }

template<class elem. Type> list. Type<elem. Type>: : ~list. Type() //destructor { delete [] list;

template<class elem. Type> list. Type<elem. Type>: : ~list. Type() //destructor { delete [] list; } template<class elem. Type> void list. Type<elem. Type>: : sort() //selection sort { int i, j; int min; elem. Type temp; for(i = 0; i <length; i++) { min = i; for(j = i+1; j < length; ++j) if(list[j] < list[min]) min = j; temp = list[i]; list[i] = list[min]; list[min] = temp; }//end for }//end sort

template<class elem. Type> void list. Type<elem. Type>: : print() const { int i; for(i

template<class elem. Type> void list. Type<elem. Type>: : print() const { int i; for(i = 0; i < length; ++i) cout<<list[i]<<" "; cout<<endl; }//end print template<class elem. Type> void list. Type<elem. Type>: : insert. At (const elem. Type& item, int position) { assert(position >= 0 && position < max. Size); list[position] = item; length++; } #endif

//Program to test the class list. Type #include <iostream> #include "list. Type. h" #include

//Program to test the class list. Type #include <iostream> #include "list. Type. h" #include "my. String. h" using namespace std; int main() { list. Type<int> int. List(100); //Line list. Type<new. String> string. List; //Line int counter; //Line int number; //Line cout<<"List 5: Processing the integer List" <<endl; //Line cout<<"List 6: Enter 5 integers: "; //Line 1 2 3 4 5 6 for(counter = 0; counter < 5; counter++)//Line 7 { cin>>number; //Line 8 int. List. insert. At(number, counter); //Line 9 }

cout<<endl; //Line 10 cout<<"List 11: The list you entered is: "; //Line 11 int.

cout<<endl; //Line 10 cout<<"List 11: The list you entered is: "; //Line 11 int. List. print(); cout<<endl; //Line 12 //Line 13 cout<<"Line 14: After sorting, the list is: "; //Line 14 int. List. sort(); //Line int. List. print(); //Line cout<<endl; //Line new. String str; //Line cout<<"Line 19: Processing the string List" <<endl; //Line cout<<"Line 20: Enter 5 strings: "; //Line for(counter = 0; counter < 5; counter++)//Line { cin>>str; //Line string. List. insert. At(str, counter); //Line } cout<<endl; //Line cout<<"Line 25: The list you entered is: " <<endl; //Line 15 16 17 18 19 20 21 22 23 24 25

string. List. print(); //Line 26 cout<<endl; //Line 27 cout<<"Line 28: After sorting, the list

string. List. print(); //Line 26 cout<<endl; //Line 27 cout<<"Line 28: After sorting, the list is: " <<endl; //Line 28 string. List. sort(); //Line 29 string. List. print(); //Line 30 cout<<endl; //Line 31 int. List. Size; //Line 32 cout<<"Line 33: Enter the size of the integer " <<list: "; //Line 33 cin>>int. List. Size; //Line 34 list. Type<int> int. List 2(int. List. Size); //Line 35 cout<<"Line 36: Processing the integer List" <<endl; //Line 36 cout<<"Line 37: Enter "<<int. List. Size <<" integers: "; //Line 37

} for(counter = 0; counter < int. List. Size; counter++) //Line 38 { cin>>number;

} for(counter = 0; counter < int. List. Size; counter++) //Line 38 { cin>>number; //Line 39 int. List 2. insert. At(number, counter); //Line 40 } cout<<endl; //Line 41 cout<<"Line 42: The list you entered is: "<<endl; //Line 42 int. List 2. print(); //Line 43 cout<<endl; //Line 44 cout<<"Line 45: After sorting, the list is: " <<endl; //Line 45 int. List 2. sort(); //Line 46 int. List 2. print(); //Line 47 cout<<endl; //Line 48 cout<<"Line 49: Length of the list = " <<int. List 2. get. Length()<<endl; //Line 49 cout<<"Line 50: Maximum size of the list = " <<int. List 2. get. Max. Size()<<endl; //Line 50 return 0;

Sample Run: In this sample run, the use input is in red. List 5:

Sample Run: In this sample run, the use input is in red. List 5: Processing the integer List 6: Enter 5 integers: 19 15 66 24 34 List 11: The list you entered is: 19 15 Line 14: After sorting, the list is: 15 66 19 24 24 34 34 66 Line 19: Processing the string List Line 20: Enter 5 strings: summer cold winter warm sunny Line 25: The list you entered is: summer cold winter warm sunny Line 28: After sorting, the list is: cold summer sunny warm winter Line 33: Enter the size of the integer list: 10 Line 36: Processing the integer List Line 37: Enter 10 integers: 23 65 34 8 11 5 3 16 45 2 Line 42: The list you entered is: 23 65 34 8 11 5 3 16 45 2 Line 45: After sorting, the list is: 2 3 5 8 11 16 23 34 45 65 Line 49: Length of the list = 10 Line 50: Maximum size of the list = 10