Operator Overloading
Operator Overloading
Examples
<<
Stream insertion, bitwise left-shift
+
Performs arithmetic on multiple types (integers, floats, etc.)
Overloading operators
Create a function for the class Name function operator followed by symbol
Operator+ for the addition operator +
8.4 Operator Functions As Class Members Vs. As Friend Functions Operator functions
Member functions
Use this keyword to implicitly get argument Gets left operand for binary operators (like +)
Leftmost object must be of same class as operator
Called when
Left operand of binary operator of same class Single operand of unitary operator of same class
8.4 Operator Functions As Class Members Vs. As Friend Functions Overloaded << operator
Left operand of type ostream &
Such as cout object in cout << classObject
Similarly, overloaded >> needs istream & Thus, both must be non-member functions
8.4 Operator Functions As Class Members Vs. As Friend Functions Commutative operators
May want + to be commutative
So both a + b and b + a work
Suppose we have two different classes Overloaded operator can only be member function when its class is on left
HugeIntClass + Long int Can be member function
10
Example program
Class PhoneNumber
Holds a telephone number
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
// Fig. 8.3: fig08_03.cpp // Overloading the stream-insertion and // stream-extraction operators. #include <iostream> using using using using using std::cout; std::cin; std::endl; std::ostream; std::istream;
11
Outline
fig08_03.cpp (1 of 3)
// PhoneNumber class definitionThey must be non-member friend class PhoneNumber { functions, since the object of class friend ostream &operator<<( ostream&, const PhoneNumber & ); Phonenumber appears on the right friend istream &operator>>( istream&, PhoneNumber & );
of
the operator.
cin << object 3-digit area code and null cout >> object
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
12
// overloaded stream-insertion operator; cannot be // a member function if we would like to invoke it with // cout << somePhoneNumber; fig08_03.cpp ostream &operator<<( ostream &output, const PhoneNumber &num ) (2 of 3) { The expression: output << "(" << num.areaCode << ") " cout << phone; << num.exchange << "-" << num.line;
Outline
return output;
is interpreted as the function call: operator<<(cout, phone); output is an alias for cout.
// overloaded stream-extraction operator; cannot be This allows objects to be cascaded. // a member function if we would like to invoke it with cout << phone1 << phone2; ignore() skips specified // cin >> somePhoneNumber; first calls istream &operator>>( istream number of characters from ) &input, PhoneNumber &num operator<<(cout, phone1), and input (1 by default). { returns cout. input.ignore(); // skip ( input >> setw( 4 ) >> num.areaCode; // input area code Next, cout << phone2 executes. input.ignore( 2 ); // skip ) and space input >> setw( 4 ) >> num.exchange; Stream manipulator setw // input exchange input.ignore(); // skip dash (-) restricts number of characters input >> setw( 5 ) >> num.line; // input line read. setw(4) allows 3 return input; // enables cin >> a >> b >> c;
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
13
} // end function operator>> int main() { PhoneNumber phone; // create object phone cout << "Enter phone number in the form (123) 456-7890:\n";
Outline
fig08_03.cpp (3 of 3) fig08_03.cpp output (1 of 1)
// cin >> phone invokes operator>> by implicitly issuing // the non-member function call operator>>( cin, phone ) cin >> phone;
cout << "The phone number entered was: " ; // cout << phone invokes operator<< by implicitly issuing // the non-member function call operator<<( cout, phone ) cout << phone << endl; return 0; } // end main
Enter phone number in the form (123) 456-7890: (800) 555-1212 The phone number entered was: (800) 555-1212
14
15
16
Upcoming example
If non-static member function, needs one argument
class String { public: const String &operator+=( const String & ); ... };
y += z equivalent to y.operator+=( z )
17
y += z equivalent to operator+=( y, z )
18
19
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
// Fig. 8.4: array1.h // Array class for storing arrays of integers. #ifndef ARRAY1_H #define ARRAY1_H #include <iostream> using std::ostream; using std::istream; class Array { friend ostream &operator<<( ostream &, const Array & ); friend istream &operator>>( istream &, Array & ); public: Array( int = 10 ); Array( const Array & ); ~Array(); int getSize() const;
20
Outline
array1.h (1 of 2)
// // // // return size
Most operators overloaded as member default constructor functions (except << and copy constructor >>, which must be nondestructor member functions). Prototype for copy constructor.
// assignment operator const Array &operator=( const Array & ); // equality operator bool operator==( const Array & ) const;
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
// inequality operator; returns opposite of == operator bool operator!=( const Array &right ) const { return ! ( *this == right ); // invokes Array::operator== } // end function operator!= // subscript operator for int &operator[]( int );
21
Outline
array1.h (2 of 2)
!= operator simply returns opposite of == operator. Thus, non-const objects returns lvalue only need to define the == operator.
// subscript operator for const objects returns rvalue const int &operator[]( int ) const; private: int size; // array size int *ptr; // pointer to first element of array }; // end class Array #endif
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
// Fig 8.5: array1.cpp // Member function definitions for class Array #include <iostream> using std::cout; using std::cin; using std::endl; #include <iomanip> using std::setw; #include <new> #include <cstdlib> #include "array1.h" // C++ standard "new" operator // exit function prototype // Array class definition
22
Outline
array1.cpp (1 of 7)
// default constructor for class Array (default size 10) Array::Array( int arraySize ) { // validate arraySize size = ( arraySize > 0 ? arraySize : 10 ); ptr = new int[ size ]; // create space for array
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
for ( int i = 0; i < size; i++ ) ptr[ i ] = 0; // initialize array } // end Array default constructor // copy constructor for class Array; // must receive a reference to prevent infinite recursion We must declare a new integer array Array::Array( const Array &arrayToCopy ) the objects do not point to the same : size( arrayToCopy.size ) memory. { ptr = new int[ size ]; // create space for array for ( int i = 0; i < size; i++ ) ptr[ i ] = arrayToCopy.ptr[ i ]; } // end Array copy constructor // destructor for class Array Array::~Array() { delete [] ptr; // reclaim array space
23
Outline
array1.cpp (2 of 7) so
} // end destructor
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
// return size of array int Array::getSize() const { return size; } // end function getSize // overloaded assignment operator; Want to avoid self-assignment. // const return avoids: ( a1 = a2 ) = a3 const Array &Array::operator=( const Array &right ) { if ( &right != this ) { // check for self-assignment // for arrays of different sizes, deallocate original // left-side array, then allocate new left-side array if ( size != right.size ) { delete [] ptr; // reclaim space size = right.size; // resize this object ptr = new int[ size ]; // create space for array copy } // end inner if
24
Outline
array1.cpp (3 of 7)
for ( int i = 0; i < size; i++ ) ptr[ i ] = right.ptr[ i ]; // copy array into object
} // end outer if
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
25
return *this; // enables x = y = z, for example
Outline
array1.cpp (4 of 7)
} // end function operator= // determine if two arrays are equal and // return true, otherwise return false bool Array::operator==( const Array &right ) const { if ( size != right.size ) return false; // arrays of different sizes for ( int i = 0; i < size; i++ ) if ( ptr[ i ] != right.ptr[ i ] ) return false; // arrays are not equal return true; // arrays are equal
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
// overloaded subscript operator for non-const Arrays // reference return creates an lvalue int &Array::operator[]( int subscript ) { // check for subscript out of range error integers1[5] calls if ( subscript < 0 || subscript >= size ) { integers1.operator[]( cout << "\nError: Subscript " << subscript << " out of range" << endl;
26
Outline
array1.cpp (5 of 7) 5 )
exit( 1 );
} // end if
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
// overloaded subscript operator for const Arrays // const reference return creates an rvalue const int &Array::operator[]( int subscript ) const { // check for subscript out of range error if ( subscript < 0 || subscript >= size ) { cout << "\nError: Subscript " << subscript << " out of range" << endl;
27
Outline
array1.cpp (6 of 7)
exit( 1 );
} // end if
return ptr[ subscript ]; // const reference return } // end function operator[] // overloaded input operator for class Array; // inputs values for entire array istream &operator>>( istream &input, Array &a ) { for ( int i = 0; i < a.size; i++ ) input >> a.ptr[ i ]; return input; } // end function // enables cin >> x >> y;
142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
28
// overloaded output operator for class Array ostream &operator<<( ostream &output, const Array &a ) { int i; // output private ptr-based array for ( i = 0; i < a.size; i++ ) { output << setw( 12 ) << a.ptr[ i ]; if ( ( i + 1 ) % 4 == 0 ) // 4 numbers per row of output output << endl; } // end for if ( i % 4 != 0 ) // end last line of output output << endl; return output; // enables cout << x << y;
Outline
array1.cpp (7 of 7)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
// Fig. 8.6: fig08_06.cpp // Array class test program. #include <iostream> using std::cout; using std::cin; using std::endl; #include "array1.h" int main() { Array integers1( 7 ); Array integers2;
29
Outline
fig08_06.cpp (1 of 3)
// print integers1 size and contents cout << "Size of array integers1 is " << integers1.getSize() << "\nArray after initialization:\n" << integers1; // print integers2 size and contents cout << "\nSize of array integers2 is " << integers2.getSize() << "\nArray after initialization:\n" << integers2;
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
// input and print integers1 and integers2 cout << "\nInput 17 integers:\n"; cin >> integers1 >> integers2; cout << "\nAfter input, the arrays contain:\n" << "integers1:\n" << integers1 << "integers2:\n" << integers2; // use overloaded inequality (!=) operator cout << "\nEvaluating: integers1 != integers2\n"; if ( integers1 != integers2 ) cout << "integers1 and integers2 are not equal\n"; // create array integers3 using integers1 as an // initializer; print size and contents Array integers3( integers1 ); // calls copy constructor cout << "\nSize of array integers3 is " << integers3.getSize() << "\nArray after initialization:\n" << integers3;
30
Outline
fig08_06.cpp (2 of 3)
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
// use overloaded assignment (=) operator cout << "\nAssigning integers2 to integers1:\n"; integers1 = integers2; // note target is smaller cout << "integers1:\n" << integers1 << "integers2:\n" << integers2; // use overloaded equality (==) operator cout << "\nEvaluating: integers1 == integers2\n"; if ( integers1 == integers2 ) cout << "integers1 and integers2 are equal\n"; // use overloaded subscript operator to create rvalue cout << "\nintegers1[5] is " << integers1[ 5 ]; // use overloaded subscript operator to create lvalue cout << "\n\nAssigning 1000 to integers1[5]\n"; integers1[ 5 ] = 1000; cout << "integers1:\n" << integers1; // attempt to use out-of-range subscript cout << "\nAttempt to assign 1000 to integers1[15]" << endl; integers1[ 15 ] = 1000; // ERROR: out of range return 0; } // end main
31
Outline
fig08_06.cpp (3 of 3)
32
Size of array integers1 is 7 Array after initialization: 0 0 0 0 Size of array integers2 is 10 Array after initialization: 0 0 0 0 0 0
Outline
0 0 0
fig08_06.cpp output (1 of 3)
0 0
0 0
3 7 10 14
11 15
Evaluating: integers1 != integers2 integers1 and integers2 are not equal Size of array integers3 is 7 Array after initialization: 1 2 5 6 Assigning integers2 to integers1: integers1: 8 9 12 13 16 17 integers2: 8 9 12 13 16 17 Evaluating: integers1 == integers2 integers1 and integers2 are equal integers1[5] is 13
33
Outline
fig08_06.cpp output (2 of 3)
3 7
10 14
11 15
10 14
11 15
34
Outline
10 14 11 15
fig08_06.cpp output (3 of 3)
35
36
Also
A::operator int() const; A::operator OtherClass() const;
37
8.9 Converting between Types Casting can prevent need for overloading
Suppose class String can be cast to char * cout << s; // s is a String
Compiler implicitly converts s to char * Do not have to overload <<
38
Conversion constructor
Single-argument constructor Turns objects of other types into class objects
String s1(hi); Creates a String from a char *
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
// Fig. 8.7: string1.h // String class definition. #ifndef STRING1_H #define STRING1_H #include <iostream> using std::ostream; using std::istream; class String { friend ostream &operator<<( ostream &, const String & ); Conversion constructor friend istream &operator>>( istream &, String & ); public: String( const char * = "" ); // conversion/default ctor String( const String & ); // copy constructor s1 += s2 ~String(); // destructor
39
Outline
string1.h (1 of 3)
to
const String &operator=( const String & ); // assignment const String &operator+=( const String & ); //Can also concatenate concatenation
bool operator!() const; // bool operator==( const String & ) const; // bool operator<( const String & ) const; //
a String and a char * because the iscompiler empty? the char * String will cast test s1 == to a String. argument s2 test s1 < s2 However, it can only do 1 level of casting.
2003 Prentice Hall, Inc.
All rights reserved.
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
// test s1 != s2 bool operator!=( const String & right ) const { return !( *this == right ); } // end function operator!= // test s1 > s2 bool operator>( const String &right ) const { return right < *this; } // end function operator> // test s1 <= s2 bool operator<=( const String &right ) const { return !( right < *this ); } // end function operator <= // test s1 >= s2 bool operator>=( const String &right ) const { return !( *this < right ); } // end function operator>=
40
Outline
string1.h (2 of 3)
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
char &operator[]( int ); // const char &operator[]( int ) const; // String operator()( int, int ); int getLength() const; private: int length; char *sPtr;
Two overloaded subscript subscript operator operators, for const and subscript operator non-const objects.
41
Outline
string1.h (3 of 3)
// return a substring // return string length Overload the function call operator () to return a substring. This operator can have any amount of operands. of string // utility function
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
// Fig. 8.8: string1.cpp // Member function definitions for class String. #include <iostream> using std::cout; using std::endl; #include <iomanip>
42
Outline
string1.cpp (1 of 8)
using std::setw;
#include <new> #include <cstring> #include <cstdlib> #include "string1.h" // C++ standard "new" operator // strcpy and strcat prototypes // exit prototype // String class definition
// conversion constructor converts char * to String String::String( const char *s ) : length( strlen( s ) ) { cout << "Conversion constructor: " << s << '\n'; setString( s ); // call utility function } // end String conversion constructor
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
43
// copy constructor String::String( const String © ) : length( copy.length ) { cout << "Copy constructor: " << copy.sPtr << '\n'; setString( copy.sPtr ); // call utility function } // end String copy constructor // destructor String::~String() { cout << "Destructor: " << sPtr << '\n'; delete [] sPtr; // reclaim string } // end ~String destructor // overloaded = operator; avoids self assignment const String &String::operator=( const String &right ) { cout << "operator= called\n"; if ( &right != this ) { delete [] sPtr; length = right.length; setString( right.sPtr ); } // // // // avoid self assignment prevents memory leak new String length call utility function
Outline
string1.cpp (2 of 8)
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
44
else cout << "Attempted assignment of a String to itself\n"; return *this; // enables cascaded assignments
Outline
string1.cpp (3 of 8)
} // end function operator= // concatenate right operand to this object and // store in this object. const String &String::operator+=( const String &right ) { size_t newLength = length + right.length; // new length char *tempPtr = new char[ newLength + 1 ]; // create memory strcpy( tempPtr, sPtr ); strcpy( tempPtr + length, right.sPtr ); delete [] sPtr; sPtr = tempPtr; length = newLength; // copy sPtr // copy right.sPtr
// reclaim old space // assign new array to sPtr // assign new length to length
return *this;
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
// is this String empty? bool String::operator!() const { return length == 0; } // end function operator! // is this String equal to right String? bool String::operator==( const String &right ) const { return strcmp( sPtr, right.sPtr ) == 0; } // end function operator== // is this String less than right String? bool String::operator<( const String &right ) const { return strcmp( sPtr, right.sPtr ) < 0; } // end function operator<
45
Outline
string1.cpp (4 of 8)
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
// return reference to character in String as lvalue char &String::operator[]( int subscript ) { // test for subscript out of range if ( subscript < 0 || subscript >= length ) { cout << "Error: Subscript " << subscript << " out of range" << endl; exit( 1 ); // terminate program
46
Outline
string1.cpp (5 of 8)
}
return sPtr[ subscript ]; } // end function operator[] // return reference to character in String as rvalue const char &String::operator[]( int subscript ) const { // test for subscript out of range if ( subscript < 0 || subscript >= length ) { cout << "Error: Subscript " << subscript << " out of range" << endl; exit( 1 ); } return sPtr[ subscript ]; } // end function operator[] // creates rvalue // terminate program // creates lvalue
131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
47
// return a substring beginning at index and // of length subLength String String::operator()( int index, int subLength ) { // if index is out of range or substring length < 0, // return an empty String object if ( index < 0 || index >= length || subLength < 0 ) return ""; // converted to a String object automatically // determine length of substring int len; if ( ( subLength == 0 ) || ( index + subLength > length ) ) len = length - index; else len = subLength; // allocate temporary array for substring and // terminating null character char *tempPtr = new char[ len + 1 ];
Outline
string1.cpp (6 of 8)
// copy substring into char array and terminate string strncpy( tempPtr, &sPtr[ index ], len ); tempPtr[ len ] = '\0';
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178
48
// create temporary String object containing the substring String tempString( tempPtr ); delete [] tempPtr; // delete temporary array return tempString; // return copy of the temporary String
Outline
string1.cpp (7 of 8)
179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199
49
// overloaded output operator ostream &operator<<( ostream &output, const String &s ) { output << s.sPtr; return output; // enables cascading
Outline
string1.cpp (8 of 8)
} // end function operator<< // overloaded input operator istream &operator>>( istream &input, String &s ) { char temp[ 100 ]; // buffer to store input input >> setw( 100 ) >> temp; s = temp; // use String class assignment operator return input; // enables cascading
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
// Fig. 8.9: fig08_09.cpp // String class test program. #include <iostream> using std::cout; using std::endl; #include "string1.h"
50
Outline
fig08_09.cpp (1 of 4)
int main() { String s1( "happy" ); String s2( " birthday" ); String s3;
// test cout << << << << << << << << << overloaded equality and relational operators "s1 is \"" << s1 << "\"; s2 is \"" << s2 "\"; s3 is \"" << s3 << '\"' "\n\nThe results of comparing s2 and s1:" "\ns2 == s1 yields " ( s2 == s1 ? "true" : "false" ) "\ns2 != s1 yields " ( s2 != s1 ? "true" : "false" ) "\ns2 > s1 yields " ( s2 > s1 ? "true" : "false" )
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
"\ns2 < s1 yields " ( s2 < s1 ? "true" : "false" ) "\ns2 >= s1 yields " ( s2 >= s1 ? "true" : "false" ) "\ns2 <= s1 yields " ( s2 <= s1 ? "true" : "false" );
51
Outline
fig08_09.cpp (2 of 4)
// test overloaded String empty (!) operator cout << "\n\nTesting !s3:\n"; if ( !s3 ) { cout << "s3 is empty; assigning s1 to s3;\n"; s3 = s1; // test overloaded assignment cout << "s3 is \"" << s3 << "\""; } // test overloaded String concatenation operator cout << "\n\ns1 += s2 yields s1 = "; s1 += s2; // test overloaded concatenation cout << s1; // test cout << s1 += " cout << conversion constructor "\n\ns1 += \" to you\" yields\n"; to you"; // test conversion constructor "s1 = " << s1 << "\n\n";
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
52
// test cout << << << // test cout << << << overloaded function call operator () for substring "The substring of s1 starting at\n" "location 0 for 14 characters, s1(0, 14), is:\n" s1( 0, 14 ) << "\n\n"; substring "to-end-of-String" option "The substring of s1 starting at\n" "location 15, s1(15, 0), is: " s1( 15, 0 ) << "\n\n"; // 0 is "to end of string"
Outline
fig08_09.cpp (3 of 4)
// test copy constructor String *s4Ptr = new String( s1 ); cout << "\n*s4Ptr = " << *s4Ptr << "\n\n"; // test assignment (=) operator with self-assignment cout << "assigning *s4Ptr to *s4Ptr\n"; *s4Ptr = *s4Ptr; // test overloaded assignment cout << "*s4Ptr = " << *s4Ptr << '\n'; // test destructor delete s4Ptr;
74 75 76 77 78 79 80 81 82 83 84 85 86
using subscript operator to create lvalue = 'H'; = 'B'; "\ns1 after s1[0] = 'H' and s1[6] = 'B' is: " s1 << "\n\n";
53
Outline
fig08_09.cpp (4 of 4)
// test subscript out of range cout << "Attempt to assign 'd' to s1[30] yields:" << endl; s1[ 30 ] = 'd'; // ERROR: subscript out of range return 0; } // end main
Conversion constructor: happy Conversion constructor: birthday Conversion constructor: s1 is "happy"; s2 is " birthday"; s3 is "" The results of comparing s2 and s1: s2 == s1 yields false s2 != s1 yields true s2 > s1 yields false s2 < s1 yields true s2 >= s1 yields false s2 <= s1 yields true Testing !s3: s3 is empty; assigning s1 to s3; operator= called s3 is "happy" s1 += s2 yields s1 = happy birthday s1 += " to you" yields Conversion constructor: to you Destructor: to you s1 = happy birthday to you
54
Outline
fig08_09.cpp (1 of 3)
The constructor and destructor are called for the temporary String (converted from the char * to you).
Conversion constructor: happy birthday Copy constructor: happy birthday Destructor: happy birthday The substring of s1 starting at location 0 for 14 characters, s1(0, 14), is: happy birthday Destructor: happy birthday Conversion constructor: to you Copy constructor: to you Destructor: to you The substring of s1 starting at location 15, s1(15, 0), is: to you Destructor: to you Copy constructor: happy birthday to you *s4Ptr = happy birthday to you assigning *s4Ptr to *s4Ptr operator= called Attempted assignment of a String to itself *s4Ptr = happy birthday to you Destructor: happy birthday to you
55
Outline
fig08_09.cpp (2 of 3)
s1 after s1[0] = 'H' and s1[6] = 'B' is: Happy Birthday to you Attempt to assign 'd' to s1[30] yields: Error: Subscript 30 out of range
56
Outline
fig08_09.cpp (3 of 3)
57
Prototype (non-member)
Friend Date &operator++( Date &); ++d1 same as operator++( d1 )
58
Prototype (non-member)
friend Date operator++( Data &, int ); d1++ same as operator++( d1, 0 )
59
Postincrement
Returns by value Returns temporary object with old value rvalue (cannot be on left side of assignment)
60
Overloaded += operator Function to test for leap years Function to determine if day is last of month
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
// Fig. 8.10: date1.h // Date class definition. #ifndef DATE1_H #define DATE1_H #include <iostream> using std::ostream; class Date { friend ostream &operator<<( ostream &, const Date & ); public: Date( int m = 1, int d = 1, int y = 1900 ); // constructor Note difference between void setDate( int, int, int ); // set the date and post increment. Date &operator++(); Date operator++( int ); // preincrement operator // postincrement operator
61
Outline
date1.h (1 of 2)
pre
const Date &operator+=( int ); // add days, modify object bool leapYear( int ) const; bool endOfMonth( int ) const; // is this a leap year? // is this end of month?
23 24 25 26 27 28 29 30 31 32 33 34
62
private: int month; int day; int year; static const int days[]; void helpIncrement(); // array of days per month // utility function
Outline
date1.h (2 of 2)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
// Fig. 8.11: date1.cpp // Date class member function definitions. #include <iostream> #include "date1.h" // initialize static member at file scope; // one class-wide copy const int Date::days[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; // Date constructor Date::Date( int m, int d, int y ) { setDate( m, d, y ); } // end Date constructor // set month, day and year void Date::setDate( int mm, int dd, int yy ) { month = ( mm >= 1 && mm <= 12 ) ? mm : 1; year = ( yy >= 1900 && yy <= 2100 ) ? yy : 1900;
63
Outline
date1.cpp (1 of 5)
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
leap year 2 && leapYear( year ) ) >= 1 && dd <= 29 ) ? dd : 1; >= 1 && dd <= days[ month ] ) ? dd : 1;
64
Outline
date1.cpp (2 of 5)
} // end function setDate // overloaded preincrement operator Date &Date::operator++() { helpIncrement(); return *this; // reference return to create an lvalue
Postincrement updates object and returns a copy of the // overloaded postincrement operator; note that the dummy original. Do not return a // integer parameter does not have a parameter name reference to temp, because it Date Date::operator++( int ) is a local variable that will be { destroyed. Date temp = *this; // hold current state of object
helpIncrement();
// return unincremented, saved, return temp; // value return; } // end function operator++
Also note that the integer temporary object parameter does not have a not a reference return name.
2003 Prentice Hall, Inc.
All rights reserved.
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
65
// add specified number of days to date const Date &Date::operator+=( int additionalDays ) { for ( int i = 0; i < additionalDays; i++ ) helpIncrement(); return *this; // enables cascading
Outline
date1.cpp (3 of 5)
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
// determine whether the day is the last day of the month bool Date::endOfMonth( int testDay ) const { if ( month == 2 && leapYear( year ) ) return testDay == 29; // last day of Feb. in leap year else return testDay == days[ month ]; } // end function endOfMonth // function to help increment the date void Date::helpIncrement() { // day is not end of month if ( !endOfMonth( day ) ) ++day; else // day is end of month and month < 12 if ( month < 12 ) { ++month; day = 1; }
66
Outline
date1.cpp (4 of 5)
100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
// last day of year else { ++year; month = 1; day = 1; } } // end function helpIncrement
67
Outline
date1.cpp (5 of 5)
// overloaded output operator ostream &operator<<( ostream &output, const Date &d ) { static char *monthName[ 13 ] = { "", "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" };
output << monthName[ d.month ] << ' ' << d.day << ", " << d.year; return output; // enables cascading
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
// Fig. 8.12: fig08_12.cpp // Date class test program. #include <iostream> using std::cout; using std::endl; #include "date1.h" // Date class definition
68
Outline
fig08_12.cpp (1 of 2)
int main() { Date d1; // defaults to January 1, 1900 Date d2( 12, 27, 1992 ); Date d3( 0, 99, 8045 ); // invalid date
cout << "d1 is " << d1 << "\nd2 is " << d2 << "\nd3 is " << d3; cout << "\n\nd2 += 7 is " << ( d2 += 7 ); d3.setDate( 2, 28, 1992 ); cout << "\n\n d3 is " << d3; cout << "\n++d3 is " << ++d3; Date d4( 7, 13, 2002 );
26 27 28 29 30 31 32 33 34 35 36 37 38 39
69
cout << << cout << cout << cout << << cout << cout << "\n\nTesting the preincrement operator:\n" " d4 is " << d4 << '\n'; "++d4 is " << ++d4 << '\n'; " d4 is " << d4; "\n\nTesting the postincrement operator:\n" " d4 is " << d4 << '\n'; "d4++ is " << d4++ << '\n'; " d4 is " << d4 << endl;
Outline
fig08_12.cpp (2 of 2)
d1 is January 1, 1900 d2 is December 27, 1992 d3 is January 1, 1900 d2 += 7 is January 3, 1993 d3 is February 28, 1992 ++d3 is February 29, 1992
70
Outline
fig08_12.cpp output (1 of 1)
Testing d4 is ++d4 is d4 is
Testing d4 is d4++ is d4 is
the preincrement operator: July 13, 2002 July 14, 2002 July 14, 2002
the postincrement operator: July 14, 2002 July 14, 2002 July 15, 2002
8.13 Standard Library Classes string and vector Classes built into C++
Available for anyone to use string
Similar to our String class
71
vector
Dynamically resizable array
72
73
Overloaded []
Access one character No range checking (if subscript invalid)
at function
s1.at(10) Character at subscript 10 Has bounds checking Will end program if invalid (learn more in Chapter 13)
2003 Prentice Hall, Inc. All rights reserved.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
// Fig. 8.13: fig08_13.cpp // Standard library string class test program. #include <iostream> using std::cout; using std::endl; #include <string>
74
Outline
fig08_13.cpp (1 of 4)
using std::string;
int main() { string s1( "happy" ); string s2( " birthday" ); string s3; // test cout << << << << << << << overloaded equality and relational operators "s1 is \"" << s1 << "\"; s2 is \"" << s2 "\"; s3 is \"" << s3 << '\"' "\n\nThe results of comparing s2 and s1:" "\ns2 == s1 yields " ( s2 == s1 ? "true" : "false" ) "\ns2 != s1 yields " ( s2 != s1 ? "true" : "false" )
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
"\ns2 > s1 yields " ( s2 > s1 ? "true" : "false" ) "\ns2 < s1 yields " ( s2 < s1 ? "true" : "false" ) "\ns2 >= s1 yields " ( s2 >= s1 ? "true" : "false" ) "\ns2 <= s1 yields " ( s2 <= s1 ? "true" : "false" );
75
Outline
fig08_13.cpp (2 of 4)
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
// test // with cout << s1 += " cout << // test cout << << << // test cout << << <<
overloaded string concatenation operator C-style string "\n\ns1 += \" to you\" yields\n"; to you"; "s1 = " << s1 << "\n\n"; string member function substr "The substring of s1 starting at location 0 for\n" "14 characters, s1.substr(0, 14), is:\n" s1.substr( 0, 14 ) << "\n\n"; substr "to-end-of-string" option "The substring of s1 starting at\n" "location 15, s1.substr(15), is:\n" s1.substr( 15 ) << '\n';
76
Outline
fig08_13.cpp (3 of 4)
// test copy constructor string *s4Ptr = new string( s1 ); cout << "\n*s4Ptr = " << *s4Ptr << "\n\n"; // test assignment (=) operator with self-assignment cout << "assigning *s4Ptr to *s4Ptr\n"; *s4Ptr = *s4Ptr; cout << "*s4Ptr = " << *s4Ptr << '\n';
74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
// test destructor delete s4Ptr; // test s1[ 0 ] s1[ 6 ] cout << << using subscript operator to create lvalue = 'H'; = 'B'; "\ns1 after s1[0] = 'H' and s1[6] = 'B' is: " s1 << "\n\n";
77
Outline
fig08_13.cpp (4 of 4)
// test subscript out of range with string member function "at" cout << "Attempt to assign 'd' to s1.at( 30 ) yields:" << endl; s1.at( 30 ) = 'd'; // ERROR: subscript out of range
return 0; } // end main
s1 is "happy"; s2 is " birthday"; s3 is "" The results of comparing s2 and s1: s2 == s1 yields false s2 != s1 yields true s2 > s1 yields false s2 < s1 yields true s2 >= s1 yields false s2 <= s1 yields true Testing s3.empty(): s3 is empty; assigning s1 to s3; s3 is "happy" s1 += s2 yields s1 = happy birthday s1 += " to you" yields s1 = happy birthday to you The substring of s1 starting at location 0 for 14 characters, s1.substr(0, 14), is: happy birthday
78
Outline
fig08_13.cpp output (1 of 2)
The substring of s1 starting at location 15, s1.substr(15), is: to you *s4Ptr = happy birthday to you assigning *s4Ptr to *s4Ptr *s4Ptr = happy birthday to you
79
Outline
fig08_13.cpp output (2 of 2)
s1 after s1[0] = 'H' and s1[6] = 'B' is: Happy Birthday to you
Attempt to assign 'd' to s1.at( 30 ) yields: abnormal program termination
80
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
// Fig. 8.14: fig08_14.cpp // Demonstrating standard library class vector. #include <iostream> using std::cout; using std::cin; using std::endl; #include <iomanip> using std::setw; #include <vector> using std::vector; void outputVector( const vector< int > & ); void inputVector( vector< int > & ); int main() { vector< int > integers1( 7 ); vector< int > integers2( 10 );
81
Outline
fig08_14.cpp (1 of 5)
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
// print integers1 size and contents cout << "Size of vector integers1 is " << integers1.size() << "\nvector after initialization:\n"; outputVector( integers1 ); // print integers2 size and contents cout << "\nSize of vector integers2 is " << integers2.size() << "\nvector after initialization:\n"; outputVector( integers2 ); // input and print integers1 and integers2 cout << "\nInput 17 integers:\n"; inputVector( integers1 ); inputVector( integers2 ); cout << "\nAfter input, the vectors contain:\n" << "integers1:\n"; outputVector( integers1 ); cout << "integers2:\n"; outputVector( integers2 ); // use overloaded inequality (!=) operator cout << "\nEvaluating: integers1 != integers2\n";
82
Outline
fig08_14.cpp (2 of 5)
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
if ( integers1 != integers2 ) cout << "integers1 and integers2 are not equal\n"; // create vector integers3 using integers1 as an // initializer; print size and contents vector< int > integers3( integers1 ); // copy constructor cout << "\nSize of vector integers3 is " << integers3.size() << "\nvector after initialization:\n"; outputVector( integers3 );
83
Outline
fig08_14.cpp (3 of 5)
// use overloaded assignment (=) operator cout << "\nAssigning integers2 to integers1:\n"; integers1 = integers2; cout << "integers1:\n"; outputVector( integers1 ); cout << "integers2:\n"; outputVector( integers1 );
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
// use overloaded equality (==) operator cout << "\nEvaluating: integers1 == integers2\n"; if ( integers1 == integers2 ) cout << "integers1 and integers2 are equal\n"; // use overloaded subscript operator to create rvalue cout << "\nintegers1[5] is " << integers1[ 5 ];
84
Outline
fig08_14.cpp (4 of 5)
// use overloaded subscript operator to create lvalue cout << "\n\nAssigning 1000 to integers1[5]\n"; integers1[ 5 ] = 1000; cout << "integers1:\n"; outputVector( integers1 );
// attempt to use out of range subscript cout << "\nAttempt to assign 1000 to integers1.at( 15 )" << endl; integers1.at( 15 ) = 1000; // ERROR: out of range return 0;
} // end main
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
// output vector contents void outputVector( const vector< int > &array ) { for ( int i = 0; i < array.size(); i++ ) { cout << setw( 12 ) << array[ i ]; if ( ( i + 1 ) % 4 == 0 ) // 4 numbers per row of output cout << endl;
85
Outline
fig08_14.cpp (5 of 5)
} // end for
if ( i % 4 != 0 ) cout << endl; } // end function outputVector // input vector contents void inputVector( vector< int > &array ) { for ( int i = 0; i < array.size(); i++ ) cin >> array[ i ];
Size of vector integers1 is 7 vector after initialization: 0 0 0 0 Size of vector integers2 is 10 vector after initialization: 0 0 0 0 0 0
86
Outline
0 0 0
fig08_14.cpp output (1 of 2)
0 0
0 0
Input 17 integers: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 After input, the vectors contain: integers1: 1 2 3 5 6 7 integers2: 8 9 10 12 13 14 16 17 Evaluating: integers1 != integers2 integers1 and integers2 are not equal
11 15
Size of vector integers3 is 7 vector after initialization: 1 2 5 6 Assigning integers2 to integers1: integers1: 8 9 12 13 16 17 integers2: 8 9 12 13 16 17 Evaluating: integers1 == integers2 integers1 and integers2 are equal integers1[5] is 13 Assigning 1000 to integers1[5] integers1: 8 9 12 1000 16 17
87
Outline
3 7 4
fig08_14.cpp output (2 of 2)
11 15
10 14
10 14
11 15
10 14
11 15