1 C++ Classes and Data Structures Jeffrey S. Childs Chapter 5 An Array Class Jeffrey S. Childs Clarion University of PA © 2008, Prentice Hall.

Slides:



Advertisements
Similar presentations
Objects and Classes Part II
Advertisements

Kernighan/Ritchie: Kelley/Pohl:
Pointers Revisited l What is variable address, name, value? l What is a pointer? l How is a pointer declared? l What is address-of (reference) and dereference.
Lecture 3 Feb 4 summary of last week’s topics and review questions (handout) Today’s goals: Chapter 1 overview (sections 1.4 to 1.6) c++ classes constructors,
1 Pointers A pointer variable holds an address We may add or subtract an integer to get a different address. Adding an integer k to a pointer p with base.
 2006 Pearson Education, Inc. All rights reserved Operator Overloading.
Rossella Lau Lecture 8, DCO10105, Semester B, DCO10105 Object-Oriented Programming and Design  Lecture 8: Polymorphism & C++ pointer  Inheritance.
Chapter 16 Templates. Copyright © 2006 Pearson Addison-Wesley. All rights reserved Learning Objectives  Function Templates  Syntax, defining 
Copyright © 2008 Pearson Addison-Wesley. All rights reserved. Chapter 9 Pointers and Dynamic Arrays.
Chapter 6. 2 Objectives You should be able to describe: Function and Parameter Declarations Returning a Single Value Pass by Reference Variable Scope.
Chapter 13: Pointers, Classes, Virtual Functions, and Abstract Classes
 2006 Pearson Education, Inc. All rights reserved Classes: A Deeper Look.
1 CISC181 Introduction to Computer Science Dr. McCoy Lecture 19 Clicker Questions November 3, 2009.
C++ Programming: Program Design Including Data Structures, Fourth Edition Chapter 13: Pointers, Classes, Virtual Functions, and Abstract Classes.
C++ Programming: From Problem Analysis to Program Design, Fourth Edition Chapter 14: Pointers, Classes, Virtual Functions, and Abstract Classes.
Modular Programming Chapter Value and Reference Parameters t Function declaration: void computesumave(float num1, float num2, float& sum, float&
1 C++ Classes and Data Structures Jeffrey S. Childs Chapter 8 Stacks and Queues Jeffrey S. Childs Clarion University of PA © 2008, Prentice Hall.
C++ Classes and Data Structures Jeffrey S. Childs
A First Book of C++: From Here To There, Third Edition2 Objectives You should be able to describe: Function and Parameter Declarations Returning a Single.
Modular Programming Chapter Value and Reference Parameters computeSumAve (x, y, sum, mean) ACTUALFORMAL xnum1(input) ynum2(input) sumsum(output)
Nirmalya Roy School of Electrical Engineering and Computer Science Washington State University Cpt S 122 – Data Structures Classes: A Deeper Look Part.
CS212: Object Oriented Analysis and Design Lecture 6: Friends, Constructor and destructors.
1 Chapter 13 Recursion. 2 Chapter 13 Topics l Meaning of Recursion l Base Case and General Case in Recursive Function Definitions l Writing Recursive.
Recursion Textbook chapter Recursive Function Call a recursive call is a function call in which the called function is the same as the one making.
February 11, 2005 More Pointers Dynamic Memory Allocation.
1 C++ Classes and Data Structures Jeffrey S. Childs Chapter 13 Recursion Jeffrey S. Childs Clarion University of PA © 2008, Prentice Hall.
1 C++ Classes and Data Structures Jeffrey S. Childs Chapter 14 Introduction to Sorting Algorithms Jeffrey S. Childs Clarion University of PA © 2008, Prentice.
Chapter 13. Procedural programming vs OOP  Procedural programming focuses on accomplishing tasks (“verbs” are important).  Object-oriented programming.
CSCI-383 Object-Oriented Programming & Design Lecture 5.
Pointers OVERVIEW.
1 C++ Classes and Data Structures Jeffrey S. Childs Chapter 3 More About Classes Jeffrey S. Childs Clarion University of PA © 2008, Prentice Hall.
CPS120: Introduction to Computer Science Functions.
ADTs and C++ Classes Classes and Members Constructors The header file and the implementation file Classes and Parameters Operator Overloading.
1 C++ Classes and Data Structures Jeffrey S. Childs Chapter 4 Pointers and Dynamic Arrays Jeffrey S. Childs Clarion University of PA © 2008, Prentice Hall.
C++ Data Types Structured array struct union class Address pointer reference Simple IntegralFloating char short int long enum float double long double.
1 Chapter 15-2 Pointers, Dynamic Data, and Reference Types Dale/Weems.
Pointers and Dynamic Memory Allocation Copyright Kip Irvine 2003, all rights reserved. Revised 10/28/2003.
Object-Oriented Programming in C++
1 C++ Classes and Data Structures Jeffrey S. Childs Chapter 2 Overloaded Operators, Class Templates, and Abstraction Jeffrey S. Childs Clarion University.
Object Oriented Programming Elhanan Borenstein Lecture #3 copyrights © Elhanan Borenstein.
C HAPTER 03 Pointers Compiled by Dr. Mohammad Alhawarat.
CS 376b Introduction to Computer Vision 01 / 23 / 2008 Instructor: Michael Eckmann.
C++ Classes and Data Structures Jeffrey S. Childs
Nyhoff, ADTs, Data Structures and Problem Solving with C++, Second Edition, © 2005 Pearson Education, Inc. All rights reserved Stacks.
CPSC 252 The Big Three Page 1 The “Big Three” Every class that has data members pointing to dynamically allocated memory must implement these three methods:
Review 1 List Data Structure List operations List Implementation Array Linked List.
Chapter 11 Friends and Overloaded Operators. Introduction to function equal // Date.h #ifndef _DATE_H_ #define _DATE_H_ class CDate { public: CDate();
CS-1030 Dr. Mark L. Hornick 1 Basic C++ State the difference between a function/class declaration and a function/class definition. Explain the purpose.
Functions Illustration of: Pass by value, reference Scope Allocation Reference: See your CS115/215 textbook.
1 C++ Classes and Data Structures Jeffrey S. Childs Chapter 11 Hash Tables Jeffrey S. Childs Clarion University of PA © 2008, Prentice Hall.
Programming Fundamentals. Topics to be covered Today Recursion Inline Functions Scope and Storage Class A simple class Constructor Destructor.
1 Classes II Chapter 7 2 Introduction Continued study of –classes –data abstraction Prepare for operator overloading in next chapter Work with strings.
EEL 3801 C++ as an Enhancement of C. EEL 3801 – Lotzi Bölöni Comments  Can be done with // at the start of the commented line.  The end-of-line terminates.
1 Chapter 6 Methods for Making Data Structures. 2 Dynamic Arrays in Data Structures In almost every data structure, we want functions for inserting and.
Engineering Classes. Objectives At the conclusion of this lesson, students should be able to: Explain why it is important to correctly manage dynamically.
Copyright © 2014 Pearson Addison-Wesley. All rights reserved. Chapter 9 Pointers and Dynamic Arrays.
Chapter 1 C++ Basics Review (Section 1.4). Classes Defines the organization of a data user-defined type. Members can be  Data  Functions/Methods Information.
1 Recall that... char str [ 8 ]; str is the base address of the array. We say str is a pointer because its value is an address. It is a pointer constant.
1 Chapter 15-1 Pointers, Dynamic Data, and Reference Types Dale/Weems.
Nirmalya Roy School of Electrical Engineering and Computer Science Washington State University Cpt S 223 – Advanced Data Structures C++ Review 2.
1 // SPECIFICATION FILE (dynarray.h) // Safe integer array class allows run-time specification // of size, prevents indexes from going out of bounds, //
Memory Management.
Motivation and Overview
Andy Wang Object Oriented Programming in C++ COP 3330
Chapter 15 Pointers, Dynamic Data, and Reference Types
Chapter 15 Pointers, Dynamic Data, and Reference Types
9-10 Classes: A Deeper Look.
9-10 Classes: A Deeper Look.
SPL – PS2 C++ Memory Handling.
Presentation transcript:

1 C++ Classes and Data Structures Jeffrey S. Childs Chapter 5 An Array Class Jeffrey S. Childs Clarion University of PA © 2008, Prentice Hall

2 Before We Begin… The Array class template uses some concepts you may not have seen before –inline –return by reference –bitwise operators & and |

3 inline Functions Function calls generally take quite a few machine language instructions and slow down program execution An inline function tells the compiler to substitute the function body into the place where the function is called; therefore, in machine language, no function is actually called An inline function, therefore, is expected to execute faster

4 inline Functions (cont.) Should we inline every function? No – if we have 20 calls to a function throughout the code, the 20 calls would be replaced by 20 copies of the function body (code gets too large) We should consider inlining when a function is heavily used inside of loops

5 Returning by Reference The return type can be a reference type A reference return type is used when a location, rather than a value, needs to be returned. A location can be used on the left side of an assignment, but a value can’t. If function foo returns a reference to a private integer, the following function call is allowed: myObject.foo( x ) = 5;

6 Bitwise AND c = a & b;

7 Bitwise OR c = a | b;

8 An Array Class Template 1 // Array.h -- class template for an adjustable array 2 // When debugging, use #define DEBUG_ARRAY above 3 // your #include Array line. When done debugging, 4 // comment out #define DEBUG_ARRAY for better 5 // performance. 6 // The constructor and the changeSize function can cause 7 //an exception to be thrown if out of heap memory. 6 7 #include 8 9 using namespace std;

9 An Array Class Template (cont.) 10 template 11 class Array 12 { 13 public: 14Array( int size ); 15inline DataType & operator [ ]( int index ); 16void changeSize( int newSize ); // will not alter values 17// unless newSize is smaller than current capacity; 18// in this case, the values from 0 to newSize // will not be altered 19inline int length( ) const;// returns current capacity 20string err( ) const; // returns error message

10 An Array Class Template (cont.) 21 private: 22DataType *elements; // points to the dynamic array 23int capacity; 24DataType dud; // returned from operator [ ] if 25 // index error occurs 26int errorCode; // contains code for error if array 27 // misuse occurs 28 }; #include "Array.cpp"

11 An Array Class Template (cont.) 1 // Array.cpp -- function definitions for an array 2 3 // Error codes -- use powers of 2 4 // 0No error. 5 // 1Nonpositive size passed into constructor. 6 // 2Invalid index was used. 7 // 4Nonpositive new size passed into changeSize 8 //function 1 = = = 0100

12 An Array Class Template (cont.) 1 // Array.cpp -- function definitions for an array 2 3 // Error codes -- use powers of 2 4 // 0No error. 5 // 1Nonpositive size passed into constructor. 6 // 2Invalid index was used. 7 // 4Nonpositive new size passed into changeSize 8 //function Example: Error code 2 can be recorded with: errorCode |= 2;

13 An Array Class Template (cont.) 1 // Array.cpp -- function definitions for an array 2 3 // Error codes -- use powers of 2 4 // 0No error. 5 // 1Nonpositive size passed into constructor. 6 // 2Invalid index was used. 7 // 4Nonpositive new size passed into changeSize 8 //function Using this technique a single integer errorCode can be used to record all types of errors that have occurred.

14 An Array Class Template (cont.) 1 // Array.cpp -- function definitions for an array 2 3 // Error codes -- use powers of 2 4 // 0No error. 5 // 1Nonpositive size passed into constructor. 6 // 2Invalid index was used. 7 // 4Nonpositive new size passed into changeSize 8 //function An errorCode of 0101 means errors 1 and 4 occurred

15 An Array Class Template (cont.) 1 // Array.cpp -- function definitions for an array 2 3 // Error codes -- use powers of 2 4 // 0No error. 5 // 1Nonpositive size passed into constructor. 6 // 2Invalid index was used. 7 // 4Nonpositive new size passed into changeSize 8 //function If error code 2 occurred, it can be detected with: if (errorCode & 2)// false if errorCode is 0101

16 An Array Class Template (cont.) 1 // Array.cpp -- function definitions for an array 2 3 // Error codes -- use powers of 2 4 // 0No error. 5 // 1Nonpositive size passed into constructor. 6 // 2Invalid index was used. 7 // 4Nonpositive new size passed into changeSize 8 //function If error code 2 occurred, it can be detected with: if (errorCode & 2)// true if errorCode is 0110

17 An Array Class Template (cont.) 9 template 10 Array ::Array( int size ) 11 { 12if ( size < 1 ) { 13capacity = 1; 14errorCode = 1; // nonpositive size 15} 16else { 17capacity = size; 18errorCode = 0; // no error 19} 20 21elements = new DataType [capacity]; 22 }

18 An Array Class Template (cont.) 23 template 24 inline DataType & Array ::operator [ ]( int index ) 25 { 26 #ifdef DEBUG_ARRAY 27if ( index = capacity ) { 28errorCode |= 2; // invalid index 29return dud; 30} 31 #endif 32return elements[ index ]; 33 } Conditional Compilation

19 An Array Class Template (cont.) 34 // will not alter values unless newSize is smaller than 35 // current capacity; in this case, the values from 0 to 36 // newSize - 1 will not be altered 37 template 38 void Array ::changeSize( int newSize ) 39 { 40if ( newSize < 1 ) 41{ 42errorCode |= 4; // nonpositive new size 43return; 44} changeSize function continued…

20 An Array Class Template (cont.) 45DataType *newArray = new DataType [newSize]; 46int limit = (newSize > capacity)? capacity : newSize; 47 48for ( int i = 0; i < limit; i++ ) 49newArray[ i ] = elements[ i ]; 50 51delete [ ] elements; 52elements = newArray; 53 54capacity = newSize; 55 } ternary operator

21 An Array Class Template (cont.) 45DataType *newArray = new DataType [newSize]; 46int limit = (newSize > capacity)? capacity : newSize; 47 48for ( int i = 0; i < limit; i++ ) 49newArray[ i ] = elements[ i ]; 50 51delete [ ] elements; 52elements = newArray; 53 54capacity = newSize; 55 } if (newSize > capacity ) limit = capacity; else limit = newSize;

22 An Array Class Template (cont.) 56 template 57 inline int Array ::length( ) const 58 { 59return capacity; 60 }

23 An Array Class Template (cont.) 61 template 62 string Array ::err( ) const 63 { 64 65if ( errorCode == 0 ) 66return "No error.\n"; err function continued…

24 An Array Class Template (cont.) 67string errorMessage = ""; 68if ( errorCode & 1 ) { // nonpositive size 69errorMessage += 70"Nonpositive size passed into constructor, so\n"; 71errorMessage += 72"the capacity was set to 1 by default.\n"; 73} 74if ( errorCode & 2 ) // invalid index 75errorMessage += "Index out of range.\n"; err function continued…

25 An Array Class Template (cont.) 76if ( errorCode & 4 ) { // nonpositive new size in 77 // changeSize 78errorMessage += 79 "Nonpositive size passed into changeSize, so\n"; 80errorMessage += 81"the size of the array was not changed.\n"; 82} 83 84return errorMessage; 85 }

26 Using the Array Class Template 1 // useArray.cpp -- a program that demonstrates the use of 2 // the Array class 3 4 #include 5 #define DEBUG_ARRAY 6 #include "Array.h" 7 8 using namespace std; 9 10 void getElements( Array & numbers ); float calcAverage( Array avnums ); To uncover problems

27 Using the Array Class Template (cont.) 13 int main( ) 14 { 15Array nums( 2 ); 16 17getElements( nums ); 18float average = calcAverage( nums ); 19 20cout << "The average is: " << average << endl; 21 22return 0; 23 }

28 Using the Array Class Template (cont.) 24 void getElements( Array & numbers ) 25 { 26int i = 0; 27 28cout << "Enter a positive integer: "; 29cin >> numbers[ i ]; 30while ( numbers[ i ] != -1 ) { 31i++; 32if ( i == numbers.length( ) ) 33numbers.changeSize( i * 2 ); 34cout << "Enter a positive integer (enter -1 to stop): "; 35cin >> numbers[ i ]; 36} getElements cont…

29 Using the Array Class Template (cont.) 37numbers.changeSize( i ); 38 39cout << "getElements: " << numbers.err( ); 40 } sets the capacity to the exact number of elements entered.

30 Using the Array Class Template (cont.) 37numbers.changeSize( i ); 38 39cout << "getElements: " << numbers.err( ); 40 } Used for debugging purposes – to uncover errors in the getElements function

31 Using the Array Class Template (cont.) 41 float calcAverage( Array avnums ) 42 { 43int sum = 0; 44for ( int i = 0; i <= avnums.length( ); i++ ) 45sum += avnums[ i ]; 46 47cout << "calcAverage: " << avnums.err( ); 48return sum / float( avnums.length( ) ); 49 } error

32 Running the Main Program The following output is given using the DEBUG_ARRAY Array feature in the main program: getElements: No error. calcAverage: Index out of range. The average is: [some wrong result]

33 After Debugging… After debugging, comment out all the debugging lines of code –don’t delete; you may need these lines of code again in future maintenance

34 After Debugging… (cont.) 1 // useArray.cpp -- a program that demonstrates the use of 2 // the Array class 3 4 #include 5 #define DEBUG_ARRAY 6 #include "Array.h" 7 8 using namespace std; 9 10 void getElements( Array & numbers ); float calcAverage( Array avnums );

35 After Debugging… (cont.) 1 // useArray.cpp -- a program that demonstrates the use of 2 // the Array class 3 4 #include 5 // #define DEBUG_ARRAY 6 #include "Array.h" 7 8 using namespace std; 9 10 void getElements( Array & numbers ); float calcAverage( Array avnums );

36 After Debugging… (cont.) 1 // useArray.cpp -- a program that demonstrates the use of 2 // the Array class 3 4 #include 5 // #define DEBUG_ARRAY 6 #include "Array.h" 7 8 using namespace std; 9 10 void getElements( Array & numbers ); float calcAverage( Array avnums ); for better array performance

37 After Debugging… (cont.) 37numbers.changeSize( i ); 38 39cout << "getElements: " << numbers.err( ); 40 } end of getElements

38 After Debugging… (cont.) 37numbers.changeSize( i ); 38 39// cout << "getElements: " << numbers.err( ); 40 } end of getElements

39 After Debugging… (cont.) 41 float calcAverage( Array avnums ) 42 { 43int sum = 0; 44for ( int i = 0; i < avnums.length( ); i++ ) 45sum += avnums[ i ]; 46 47cout << "calcAverage: " << avnums.err( ); 48return sum / float( avnums.length( ) ); 49 }

40 After Debugging… (cont.) 41 float calcAverage( Array avnums ) 42 { 43int sum = 0; 44for ( int i = 0; i < avnums.length( ); i++ ) 45sum += avnums[ i ]; 46 47// cout << "calcAverage: " << avnums.err( ); 48return sum / float( avnums.length( ) ); 49 }

41 Destructors A destructor is a function that is called automatically whenever an object is destroyed If an Array object is declared within a function, the Array object will be destroyed at the end of the function. However, the dynamic array is not freed, causing memory leak, unless we write a destructor for the Array class.

42 Function Prototype for Destructor The function name for the destructor must be the class name preceded by a tilde. The destructor function cannot pass in parameters and it has no return type (the client does not call it) The destructor function prototype for the Array class would look like this: ~Array( );

43 template Array ::~Array( ) { delete [ ] elements; } Destructor in Class Implementation File

44 Ways in which Destructors are Called When an object is declared locally within a function and the end of the function is reached (More generally) when an object is declared within a block of code (under a loop, etc.), and execution leaves the block of code At the end of program execution, the destructors for any remaining objects are called (if written)

45 Ways in which Destructors are Called (cont.) When an object is created in the heap, then delete is used on the pointer to it. For example, Array *ptr = new Array (10); ….// other code ….. delete ptr; Calls the destructor.

46 Problems With Passing Parameters foo( arr );..// other code. void foo( Array arr2 ) {.. // function code. } arr, an Array object, is passed by value into function foo

47 Problems With Passing Parameters (cont.) foo( arr );..// other code. void foo( Array arr2 ) {.. // function code. } arr is called an actual parameter – the parameter in the function call arr2 is called a formal parameter – the parameter in the function heading

48 Problems With Passing Parameters (cont.) foo( arr );..// other code. void foo( Array arr2 ) {.. // function code. } arr int errorCode: 0 int capacity: 4 int *elements: The address stored in elements is the address of a dynamic array with 4 elements

49 Problems With Passing Parameters (cont.) foo( arr );..// other code. void foo( Array arr2 ) {.. // function code. } arr int errorCode: 0 int capacity: 4 int *elements:

50 Problems With Passing Parameters (cont.) foo( arr );..// other code. void foo( Array arr2 ) {.. // function code. } arr int errorCode: 0 int capacity: 4 int *elements: When arr is passed into function foo, a copy of each data member’s value is made.

51 Problems With Passing Parameters (cont.) foo( arr );..// other code. void foo( Array arr2 ) { } arr int errorCode: 0 int capacity: 4 int *elements: arr2 int errorCode: 0 int capacity: 4 int *elements: But then the elements pointer in arr2 points to the same array!

52 Problems With Passing Parameters (cont.) foo( arr );..// other code. void foo( Array arr2 ) { } arr int errorCode: 0 int capacity: 4 int *elements: arr2 int errorCode: 0 int capacity: 4 int *elements: Problem 1: Changes in the array are reflected back to the caller.

53 Problems With Passing Parameters (cont.) foo( arr );..// other code. void foo( Array arr2 ) { } arr int errorCode: 0 int capacity: 4 int *elements: arr2 int errorCode: 0 int capacity: 4 int *elements: (this isn’t what we want in pass by value!)

54 Problems With Passing Parameters (cont.) foo( arr );..// other code. void foo( Array arr2 ) { } arr int errorCode: 0 int capacity: 4 int *elements: arr2 int errorCode: 0 int capacity: 4 int *elements: When foo finishes execution, arr2 will be destroyed…

55 Problems With Passing Parameters (cont.) foo( arr );..// other code. void foo( Array arr2 ) { } arr int errorCode: 0 int capacity: 4 int *elements: arr2 int errorCode: 0 int capacity: 4 int *elements: calling the destructor for arr2 and freeing the dynamic array!

56 Problems With Passing Parameters (cont.) foo( arr );..// other code. void foo( Array arr2 ) { } arr int errorCode: 0 int capacity: 4 int *elements: 51030

57 Problems With Passing Parameters (cont.) foo( arr );..// other code. void foo( Array arr2 ) { } arr int errorCode: 0 int capacity: 4 int *elements: One can safely say that this isn’t what we want either! (Problem 2)

58 Problems With Passing Parameters (cont.) foo( arr );..// other code. void foo( Array arr2 ) { } arr int errorCode: 0 int capacity: 4 int *elements: This is called a dangling pointer or a dangling reference.

59 Copy Constructor – the Solution A copy constructor is a special class function that is called automatically when an object of the class is passed by value. The programmer does not call the copy constructor explicitly. When a copy constructor is written, data members are not copied one by one from the actual parameter to the formal parameter – instead, the code in the copy constructor is followed to do the copying.

60 Copy Constructor – the Solution (cont.) A copy constructor is a lot like a constructor (its name is the class name) What distinguishes it is that it passes in an object as a parameter, which belongs to the same class as the object that owns the copy constructor. The function prototype looks like: Array( const Array & ap ); The copy constructor is called for the formal parameter (arr2 in our example)

61 Copy Constructor – the Solution (cont.) Array( const Array & ap ); The object passed into the copy constructor is the actual parameter in the function call (arr in our example)

62 Copy Constructor – the Solution (cont.) Array( const Array & ap ); The object must be passed into the copy constructor by reference passing it by value into the copy constructor would cause another call to the copy constructor (remember that the copy constructor is called automatically when an object is passed by value). –Something similar to an infinite loop results.

63 Copy Constructor – the Solution (cont.) Array( const Array & ap ); It is passed by const reference since a change to the actual parameter should not occur (the compiler would catch it)

64 Shallow Copy vs. Deep Copy A shallow copy occurs when an address of a pointer in one object is copied into the pointer of another object (it led to the problems we saw earlier) A deep copy is a copy made without copying addresses; it is necessary to allocate more dynamic memory for the object copy to avoid copying addresses

65 Shallow Copy foo( arr );..// other code. void foo( Array arr2 ) { } arr int errorCode: 0 int capacity: 4 int *elements: arr2 int errorCode: 0 int capacity: 4 int *elements: 51030

66 Deep Copy foo( arr );..// other code. void foo( Array arr2 ) { } arr int errorCode: 0 int capacity: 4 int *elements: arr2 int errorCode: 0 int capacity: 4 int *elements:

67 Similar Problems from Object Assignment Recall that the object of one struct can be assigned to another object of the same struct, without overloading the = operator: myCar = yourCar; This is also true with objects that belong to the same class When using assignment on objects of the same class, all the values of the data members are copied; nothing happens with the function members

68 Similar Problems with Object Assignment (cont.) However, this means that a shallow copy takes place when data members are pointers Again, the elements pointers of both Array objects will point to the same array, creating problems

69 The Solution for Object Assignment The solution is to write an overloaded assignment operator (=) for the Array class This overloaded operator function would make a deep copy as well.

70 The deepCopy Function Both the copy constructor and the overloaded assignment operator function need to make deep copies We’ll make a deepCopy function, and call the function from both of these functions

71 The Copy Constructor Definition for Array template Array ::Array( const Array & ap ) { deepCopy( ap ); }

72 The Copy Constructor Process foo( arr );..// other code. void foo( Array arr2 ) {.. // function code. } First, the foo function call is made…

73 The Copy Constructor Process (cont.) foo( arr );..// other code. void foo( Array arr2 ) {.. // function code. } Pass by value is used, so the copy constructor is automatically called (a copy constructor is not called in pass by reference)

74 The Copy Constructor Process (cont.) foo( arr );..// other code. void foo( Array arr2 ) template Array ::Array( const Array & ap ) { deepCopy( ap ); } The copy constructor for arr2 executes

75 The Copy Constructor Process (cont.) foo( arr );..// other code. void foo( Array arr2 ) template Array ::Array( const Array & ap ) { deepCopy( ap ); } arr is passed as the parameter into the copy constructor function heading

76 The Copy Constructor Process (cont.) foo( arr );..// other code. void foo( Array arr2 ) template Array ::Array( const Array & ap ) { deepCopy( ap ); } the deepCopy function executes using ap (arr) as the original

77 ap (or arr) int errorCode: 0 int capacity: 4 int *elements: The Copy Constructor Process (cont.) The deepCopy function produces a deep copy of the ap (or arr) Array object, for arr2.

78 int errorCode: 0 int capacity: 4 int *elements: arr2 int errorCode: 0 int capacity: 4 int *elements: The Copy Constructor Process (cont.) The deepCopy function produces a deep copy of the ap (or arr) Array object, for arr2. ap (or arr)

79 The Copy Constructor Process (cont.) foo( arr );..// other code. void foo( Array arr2 ) template Array ::Array( const Array & ap ) { deepCopy( ap ); } the deepCopy function returns, then the copy constructor returns.

80 The Copy Constructor Process (cont.) foo( arr );..// other code. void foo( Array arr2 ) arr2 now has a deep copy of the arr object (parameter passing has completed)

81 foo( arr );..// other code. void foo( Array arr2 ) { } arr int errorCode: 0 int capacity: 4 int *elements: arr2 int errorCode: 0 int capacity: 4 int *elements: The Copy Constructor Process (cont.)

82 The Copy Constructor Process (cont.) foo( arr );..// other code. void foo( Array arr2 ) {.. // function code. } The foo function executes.

83 The deepCopy Function is Private private: DataType *elements; int capacity; DataType dud; int errorCode; inline void deepCopy( const Array & original ); The deepCopy function is placed into the private section of the Array class template.

84 The deepCopy Function is Private (cont.) private: DataType *elements; int capacity; DataType dud; int errorCode; inline void deepCopy( const Array & original ); It will only be called by the copy constructor and the overloaded assignment operator (the client cannot call it).

85 Nuts and Bolts of the deepCopy Function 1 template 2 inline void Array ::deepCopy( 3 const Array & original ) 4 { 5capacity = original.capacity; 6errorCode = original.errorCode; 7elements = new DataType [capacity]; 8for ( int i = 0; i < capacity; i++ ) 9elements[ i ] = original.elements[ i ]; 10 } from copy constructor: deepCopy( ap );

86 Nuts and Bolts of the deepCopy Function (cont.) 1 template 2 inline void Array ::deepCopy( 3 const Array & original ) 4 { 5capacity = original.capacity; 6errorCode = original.errorCode; 7elements = new DataType [capacity]; 8for ( int i = 0; i < capacity; i++ ) 9elements[ i ] = original.elements[ i ]; 10 } capacity of arr2 (in our example)

87 Nuts and Bolts of the deepCopy Function (cont.) 1 template 2 inline void Array ::deepCopy( 3 const Array & original ) 4 { 5capacity = original.capacity; 6errorCode = original.errorCode; 7elements = new DataType [capacity]; 8for ( int i = 0; i < capacity; i++ ) 9elements[ i ] = original.elements[ i ]; 10 } capacity of arr (in our example)

88 Nuts and Bolts of the deepCopy Function (cont.) 1 template 2 inline void Array ::deepCopy( 3 const Array & original ) 4 { 5capacity = original.capacity; 6errorCode = original.errorCode; 7elements = new DataType [capacity]; 8for ( int i = 0; i < capacity; i++ ) 9elements[ i ] = original.elements[ i ]; 10 }

89 Ways That Copy Constructors Are Called When passing an object by value When returning an object by value When an object is initialized in its declaration Array arr = arr2; –This does not call the overloaded assignment operator (the overloaded assignment operator is only called when the object on the left is not being declared) –The copy constructor is called for arr, and arr2 is passed in as the parameter into the copy constructor

90 Array Object Assignment If an overloaded assignment operator is not written for the Array class template, then assigning one Array object to another will produce a shallow copy of the first –their elements pointers will point to the same dynamic array An overloaded assignment operator would be written for a deep copy –calls our deepCopy function

91 Array Object Assignment (cont.) But some issues exist in assignment that don’t exist in parameter passing Consider…

92 int errorCode: 0 int capacity: 5 int *elements: arr2 int errorCode: 0 int capacity: 4 int *elements: Array Object Assignment (cont.) arr 59 Given these initial Array objects, what happens in the deepCopy function for arr = arr2;

93 int errorCode: 0 int capacity: 5 int *elements: arr2 int errorCode: 0 int capacity: 4 int *elements: Array Object Assignment (cont.) arr 59 arr = arr2; The original is arr2 – the deepCopy function is called for arr

94 int errorCode: 0 int capacity: 5 int *elements: arr2 int errorCode: 0 int capacity: 4 int *elements: Array Object Assignment (cont.) arr 59 arr = arr2; from deepCopy: capacity = original.capacity; errorCode = original.errorCode; elements = new DataType [capacity];

95 int errorCode: 0 int capacity: 5 int *elements: arr2 int errorCode: 0 int capacity: 4 int *elements: Array Object Assignment (cont.) arr 59 arr = arr2; from deepCopy: capacity = original.capacity; errorCode = original.errorCode; elements = new DataType [capacity];

96 int errorCode: 0 int capacity: 4 int *elements: arr2 int errorCode: 0 int capacity: 4 int *elements: Array Object Assignment (cont.) arr 59 arr = arr2; from deepCopy: capacity = original.capacity; errorCode = original.errorCode; elements = new DataType [capacity];

97 int errorCode: 0 int capacity: 4 int *elements: arr2 int errorCode: 0 int capacity: 4 int *elements: Array Object Assignment (cont.) arr 59 arr = arr2; from deepCopy: capacity = original.capacity; errorCode = original.errorCode; elements = new DataType [capacity];

98 int errorCode: 0 int capacity: 4 int *elements: arr2 int errorCode: 0 int capacity: 4 int *elements: Array Object Assignment (cont.) arr 59 arr = arr2; from deepCopy: capacity = original.capacity; errorCode = original.errorCode; elements = new DataType [capacity];

99 int errorCode: 0 int capacity: 4 int *elements: arr2 int errorCode: 0 int capacity: 4 int *elements: Array Object Assignment (cont.) arr 59 arr = arr2; from deepCopy: capacity = original.capacity; errorCode = original.errorCode; elements = new DataType [capacity];

100 from deepCopy: capacity = original.capacity; errorCode = original.errorCode; elements = new DataType [capacity]; int errorCode: 0 int capacity: 4 int *elements: arr2 int errorCode: 0 int capacity: 4 int *elements: Array Object Assignment (cont.) arr arr = arr2;

101 from deepCopy: capacity = original.capacity; errorCode = original.errorCode; elements = new DataType [capacity]; int errorCode: 0 int capacity: 4 int *elements: arr2 int errorCode: 0 int capacity: 4 int *elements: Array Object Assignment (cont.) arr MEMORY LEAK! arr = arr2;

102 Array Object Assignment (cont.) To solve this problem, we must free the elements array in arr first, before calling deepCopy…

103 Array Object Assignment (cont.) template ……………….. ::operator =( const Array & right ) {. delete [ ] elements; deepCopy( right );. }

104 Array Object Assignment (cont.) template ……………….. ::operator =( const Array & right ) {. delete [ ] elements; deepCopy( right );. } But we still need to put in some missing pieces…

105 Multiple Assignment In normal types of assignment, we can do this: x = y = z = 0; so we should also be able to do this: arr1 = arr2 = arr3;

106 arr1 = arr2 = arr3; How Multiple Assignment Works

107 arr1 = arr2 = arr3; Evaluated first – assignment is right associate The overloaded assignment operator is called for arr2 – it also returns arr2 when completed Then arr2 replaces this expression, just like the expression is replaced by 7 How Multiple Assignment Works (cont.)

108 arr1 = arr2; After the replacement, the next assignment can be done. This would not be possible if arr2 were not returned from the overloaded assignment operator function. How Multiple Assignment Works (cont.)

109 template ……………….. ::operator =( const Array & right ) {. delete [ ] elements; deepCopy( right );. } But how can this function return the object that it is called for? How Multiple Assignment Works (cont.)

110 this A correctly written overloaded assignment operator function uses a this pointer in a couple of places The keyword this can be used in function definitions for structs and classes It is a pointer to the object that owns the function being executed

111 template ……………….. ::operator =( const Array & right ) {. delete [ ] elements; deepCopy( right ); return *this; } Return *this

112 template ……………….. ::operator =( const Array & right ) {. delete [ ] elements; deepCopy( right ); return *this; } Return *this (cont.) Now we can fill in this part…

113 template Array Array ::operator =( const Array & right ) {. delete [ ] elements; deepCopy( right ); return *this; } Return *this (cont.) Now we can fill in this part…

114 template Array Array ::operator =( const Array & right ) {. delete [ ] elements; deepCopy( right ); return *this; } Return *this (cont.) Return type

115 template Array Array ::operator =( const Array & right ) {. delete [ ] elements; deepCopy( right ); return *this; } Return *this (cont.) The usual class name

116 template Array Array ::operator =( const Array & right ) {. delete [ ] elements; deepCopy( right ); return *this; } Return *this (cont.) We can make another improvement by recalling that return by value calls the copy constructor…

117 template Array Array ::operator =( const Array & right ) {. delete [ ] elements; deepCopy( right ); return *this; } Return *this (cont.) so let’s speed things up a bit and return by reference

118 template Array & Array ::operator =( const Array & right ) {. delete [ ] elements; deepCopy( right ); return *this; } Return *this (cont.) so let’s speed things up a bit and return by reference

119 template Array & Array ::operator =( const Array & right ) {. delete [ ] elements; deepCopy( right ); return *this; } Return *this (cont.) It is OK to return by reference in this case, because the object on the left of the assignment will still be around after we return. (Local objects should not be returned by reference – why?)

120 template Array & Array ::operator =( const Array & right ) {. delete [ ] elements; deepCopy( right ); return *this; } Return *this (cont.) We still have one more piece of the puzzle

121 template Array & Array ::operator =( const Array & right ) {. delete [ ] elements; deepCopy( right ); return *this; } An Object Assigned to Itself Consider an array of Array objects – an Array object assignment can be done like this: arr[ i ] = arr[ j ]; What happens if i == j?

122 template Array & Array ::operator =( const Array & right ) {. delete [ ] elements; deepCopy( right ); return *this; } An Object Assigned to Itself (cont.) arr[ i ] = arr[ j ]; What happens if i == j? The same Array object is assigned to itself! (This can happen in some sorting algorithms.)

123 template Array & Array ::operator =( const Array & right ) {. delete [ ] elements; deepCopy( right ); return *this; } An Object Assigned to Itself (cont.) What happens if an Array object is assigned to itself here?

124 template Array & Array ::operator =( const Array & right ) {. delete [ ] elements; deepCopy( right ); return *this; } An Object Assigned to Itself (cont.) This line frees the dynamic array of the Array object on the left of the assignment, and (consequently) the dynamic array of the object on the right of the assignment!

125 template Array & Array ::operator =( const Array & right ) { if ( this == &right ) return *this; delete [ ] elements; deepCopy( right ); return *this; } Tests to see if the address of the object on the left has the same address as the object on the right. An Object Assigned to Itself (cont.)

126 template Array & Array ::operator =( const Array & right ) { if ( this == &right ) return *this; delete [ ] elements; deepCopy( right ); return *this; } An Object Assigned to Itself (cont.) If they are the same object, return right away.

127 template Array & Array ::operator =( const Array & right ) { if ( this == &right ) return *this; delete [ ] elements; deepCopy( right ); return *this; } Complete Overloaded Assignment Operator

128 Guidelines for Writing Overloaded Assignment Operators Check to see if the objects on both sides of the assignment are the same; if so, just return *this Free the dynamic memory pointed to by all pointers in the object on the left Call a deepCopy function Return *this whenever you need to return

129 To Summarize When a class has a pointer data member that will point to dynamic memory, you need to write three functions for the class: –a destructor –a copy constructor –an overloaded assignment operator