Transcript Document

Review of C++ Programming
Part II
Sheng-Fang Huang
Composition: Objects as Members
of Classes
• Composition
– A class can have objects of other classes as
members
• Example
– AlarmClock object with a Time object as a member
– A common form of software reusability is
composition, in which a class has objects of
other classes as members.
Composition: Objects as Members
of Classes
• Initializing member objects
– Member initializers pass arguments from the
object’s constructor to member-object
constructors
– If a member initializer is not provided
• A compilation error occurs if the member object’s
class does not provide any proper constructor.
1
// Fig. 10.10: Date.h
2
// Date class definition; Member functions defined in Date.cpp
3
#ifndef DATE_H
4
#define DATE_H
5
6
class Date
7
{
8
public:
9
Date( int = 1, int = 1, int = 1900 ); // default constructor
10
void print() const; // print date in month/day/year format
11
~Date(); // provided to confirm destruction order
12 private:
13
int month; // 1-12 (January-December)
14
int day; // 1-31 based on month
15
int year; // any year
16
17
// utility function to check if day is proper for month and year
18
int checkDay( int ) const;
19 }; // end class Date
20
21 #endif
1
// Fig. 10.11: Date.cpp
2
3
// Member-function definitions for class Date.
#include <iostream>
4
using std::cout;
5
6
using std::endl;
7
8
9
#include "Date.h" // include Date class definition
// constructor confirms proper value for month; calls
10 // utility function checkDay to confirm proper value for day
11 Date::Date( int mn, int dy, int yr )
12 {
13
if ( mn > 0 && mn <= 12 ) // validate the month
14
15
month = mn;
else
16
{
17
month = 1; // invalid month set to 1
18
19
20
21
cout << "Invalid month (" << mn << ") set to 1.\n";
} // end else
22
day = checkDay( dy ); // validate the day
year = yr; // could validate yr
23
24
25
26
// output Date object to show when its constructor is called
cout << "Date object constructor for date ";
print();
27
cout << endl;
28 } // end Date constructor
29
30 // print Date object in form month/day/year
31 void Date::print() const
32 {
33
cout << month << '/' << day << '/' << year;
34 } // end function print
35
36 // output Date object to show when its destructor is called
37 Date::~Date()
38 {
39
cout << "Date object destructor for date ";
40
print();
41
cout << endl;
42 } // end ~Date destructor
1
// Fig. 10.12: Employee.h
2
// Employee class definition.
3
// Member functions defined in Employee.cpp.
4
#ifndef EMPLOYEE_H
5
#define EMPLOYEE_H
6
7
#include "Date.h" // include Date class definition
8
9
class Employee
10 {
11 public:
12
13
Parameters to be passed via member
initializers to the constructor for class Date
Employee( const char * const, const char * const,
const Date &, const Date & );
14
void print() const;
15
~Employee(); // provided to confirm destruction order
16 private:
const objects of class Date as members
17
char firstName[ 25 ];
18
char lastName[ 25 ];
19
const Date birthDate; // composition: member object
20
const Date hireDate; // composition: member object
21 }; // end class Employee
22
23 #endif
1
// Fig. 10.13: Employee.cpp
2
// Member-function definitions for class Employee.
3
#include <iostream>
4
using std::cout;
5
using std::endl;
6
7
#include <cstring> // strlen and strncpy prototypes
8
using std::strlen;
9
using std::strncpy;
10
11 #include "Employee.h" // Employee class definition
12 #include "Date.h" // Date class definition
13
14 // constructor uses member initializer list to pass initializer
15 // values to constructors of member objects birthDate and hireDate
16 // [Note: This invokes the so-called "default copy constructor" which the
17 // C++ compiler provides implicitly.]
18 Employee::Employee( const char * const first, const char * const last,
19
const Date &dateOfBirth, const Date &dateOfHire )
20
: birthDate( dateOfBirth ), // initialize birthDate
21
hireDate( dateOfHire ) // initialize hireDate
22 {
23
Member
// copy first into firstName and be sure
that initializers
it fits
that pass arguments to
Date’s implicit default copy constructor
24
int length = strlen( first );
25
length = ( length < 25 ? length : 24 );
26
strncpy( firstName, first, length );
27
firstName[ length ] = '\0';
1
// Fig. 10.14: fig10_14.cpp
2
// Demonstrating composition--an object with member objects.
3
#include <iostream>
4
using std::cout;
5
using std::endl;
6
7
#include "Employee.h" // Employee class definition
8
9
int main()
10 {
11
Date birth( 7, 24, 1949 );
12
Date hire( 3, 12, 1988 );
13
Employee manager( "Bob", "Blue", birth, hire );
14
15
cout << endl;
16
manager.print();
Passing objects to a host object constructor
17
18
cout << "\nTest Date constructor with invalid values:\n";
19
Date lastDayOff( 14, 35, 1994 ); // invalid month and day
20
cout << endl;
21
return 0;
22 } // end main
friend
• To declare a function as a friend of a
class:
– Provide the function prototype in the class
definition preceded by keyword friend.
• To declare a class as a friend of a class:
– Place a declaration of the form
friend class ClassTwo;
in the definition of class ClassOne
• All member functions of class ClassTwo are
friends of class ClassOne
friend Classes
• Friendship is granted, not taken
– For class B to be a friend of class A, class A must
explicitly declare that class B is its friend
• Friendship relation is neither symmetric nor
transitive
– If class A is a friend of class B, and class B is a
friend of class C, you cannot infer that class B is a
friend of class A, that class C is a friend of class B,
or that class A is a friend of class C
• Place all friendship declarations first inside
the class definition’s body and do not
precede them with any access specifier.
1
// Fig. 10.15: fig10_15.cpp
2
// Friends can access private members of a class.
3
#include <iostream>
4
using std::cout;
5
using std::endl;
6
7
// Count class definition
8
class Count
9
{
10
friend function declaration (can
appear anywhere in the class)
friend void setX( Count &, int ); // friend declaration
11 public:
12
// constructor
13
Count()
: x( 0 ) // initialize x to 0
14
15
{
// empty body
16
17
} // end constructor Count
18
19
// output x
20
void print() const
21
{
22
23
cout << x << endl;
} // end function print
24 private:
25
int x; // data member
26 }; // end class Count
27
28 // function setX can modify private data of Count
29 // because setX is declared as a friend of Count (line 10)
30 void setX( Count &c, int val )
31 {
32
c.x = val; // allowed because setX is a friend of Count
33 } // end function setX
34
35 int main()
friend function can modify Count’s private data
36 {
37
Count counter; // create Count object
38
39
cout << "counter.x after instantiation: ";
40
counter.print();
Calling a friend function; note that we
pass the Count object to the function
41
42
setX( counter, 8 ); // set x using a friend function
43
cout << "counter.x after call to setX friend function: ";
44
counter.print();
45
return 0;
46 } // end main
counter.x after instantiation: 0
counter.x after call to setX friend function: 8
Dynamic Memory Management
with Operators new and delete
• Dynamic memory management
– Enables programmers to allocate and
deallocate memory for any built-in or userdefined type
– Performed by operators new and delete
– For example, dynamically allocating memory
for an array instead of using a fixed-size array
Dynamic Memory Management
with Operators new and delete
• Operator new
– Allocates (i.e., reserves) storage of the proper size for
an object at execution time
– Calls a constructor to initialize the object
– Returns a pointer of the type specified to the right of
new
– Can be used to dynamically allocate any fundamental
type (such as int or double) or any class type
• Heap
– Region of memory assigned to each program for
storing objects created at execution time
Dynamic Memory Management
with Operators new and delete
• Operator delete
– Destroys a dynamically allocated object
– Calls the destructor for the object
– Deallocates (i.e., releases) memory from the
heap
– The memory can then be reused by the
system to allocate other objects
• Not releasing dynamically allocated memory when
it is no longer needed can cause the system to run
out of memory prematurely. This is sometimes
called a “memory leak.”
Dynamic Memory Management
with Operators new and delete
• new operator can be used to allocate
arrays dynamically
– Dynamically allocate a 10-element integer
array:
int *gradesArray = new int[ 10 ];
– Size of a dynamically allocated array
• Specified using any integral expression that can be
evaluated at execution time
Dynamic Memory Management
with Operators new and delete
• Delete a dynamically allocated array:
delete [] gradesArray;
– If the pointer points to an array of objects
• First calls the destructor for every object in the
array
• Then deallocates the memory
– If the statement did not include the square
brackets ([]) and gradesArray pointed to
an array of objects
• Only the first object in the array would have a
destructor call
static Class Members
• static data member
– Only one copy of a variable shared by all
objects of a class
• “Class-wide” information
• A property of the class shared by all instances, not
a property of a specific object of the class
– Declaration begins with keyword static
static Class Members
• static member function
– Is a service of the class, not of a specific
object of the class
• static applied to an item at file scope
– That item becomes known only in that file
– The static members of the class need to be
available from any client code that accesses
the file
• So we cannot declare them static in the .cpp
file—we declare them static only in the .h file.
static Class Members
• Use static data members to save
storage when a single copy of the data
for all objects of a class will suffice.
• A class’s static data members and
static member functions exist and
can be used even if no objects of that
class have been instantiated.
1
// Fig. 10.21: Employee.h
2
// Employee class definition.
3
#ifndef EMPLOYEE_H
4
#define EMPLOYEE_H
5
6
class Employee
7
{
8
public:
9
Employee( const char * const, const char * const ); // constructor
10
~Employee(); // destructor
11
const char *getFirstName() const; // return first name
12
const char *getLastName() const; // return last name
13
14
// static member function
15
static int getCount(); // return number of objects instantiated
16 private:
17
char *firstName;
18
char *lastName;
Function prototype for static member function
19
20
// static data
21
static int count; // number of objects instantiated
22 }; // end class Employee
23
24 #endif
static data member keeps track of number
of Employee objects that currently exist
1
// Fig. 10.22: Employee.cpp
2
// Member-function definitions for class Employee.
3
#include <iostream>
4
using std::cout;
5
using std::endl;
6
7
#include <cstring> // strlen and strcpy prototypes
8
using std::strlen;
9
using std::strcpy;
10
11 #include "Employee.h" // Employee class definition
12
13 // define and initialize static data member at file scope
14 int Employee::count = 0;
15
static
datanumber
member
16 // define static member function that
returns
of
17 // Employee objects
is defined and
at file scope
in the .cpp file
instantiated initialized
(declared static
in Employee.h)
18 int Employee::getCount()
19 {
20
return count;
21 } // end static function getCount
static member function can access
only static data, because the function
might be called when no objects exist
22
23 // constructor dynamically allocates space for first and last name and
24 // uses strcpy to copy first and last names into the object
25 Employee::Employee( const char * const first, const char * const last )
26 {
27
firstName = new char[ strlen( first ) + 1 ];
28
29
30
strcpy( firstName, first );
31
32
strcpy( lastName, last );
33
34
count++; // increment static count of employees
35
36
cout << "Employee constructor for " << firstName
<< ' ' << lastName << " called." << endl;
lastName = new char[ strlen( last ) + 1 ];
37 } // end Employee constructor
38
39 // destructor deallocates dynamically allocated memory
40 Employee::~Employee()
41 {
42
cout << "~Employee() called for " << firstName
43
<< ' ' << lastName << endl;
44
45
46
47
delete [] firstName; // release memory
delete [] lastName; // release memory
48
count--; // decrement static count of employees
49 } // end ~Employee destructor
Non-static member function
(i.e., constructor) can modify the
class’s static data members
1
// Fig. 10.23: fig10_23.cpp
2
3
4
// Driver to test class Employee.
#include <iostream>
using std::cout;
5
6
7
8
9
10
using std::endl;
11
12
13
14
15
16
#include "Employee.h" // Employee class definition
int main()
{
// use class name and binary scope resolution operator to
// access static number function getCount
cout << "Number of employees before instantiation of any objects is "
<< Employee::getCount() << endl; // use class name
// use new to dynamically create two new Employees
Calling static member function using class
name and binary scope resolution operator
17
18
19
20
21
// operator new also calls the object's constructor
Employee *e1Ptr = new Employee( "Susan", "Baker" );
Employee *e2Ptr = new Employee( "Robert", "Jones" );
22
cout << "Number of employees after objects are instantiated is "
23
// call getCount on first Employee object
Dynamically creating Employees with new
<< e1Ptr->getCount();
24
25
cout << "\n\nEmployee 1: "
Calling a static member function
through a pointer to an object of the class
26
27
<< e1Ptr->getFirstName() << " " << e1Ptr->getLastName()
<< "\nEmployee 2: "
28
<< e2Ptr->getFirstName() << " " << e2Ptr->getLastName() << "\n\n";
29
30
delete e1Ptr; // deallocate memory
31
e1Ptr = 0; // disconnect pointer from free-store space
32
delete e2Ptr; // deallocate memory
33
e2Ptr = 0; // disconnect pointer from free-store space
34
35
// no objects exist, so call static member function getCount again
36
// using the class name and the binary scope resolution operator
37
cout << "Number of employees after objects are deleted is "
38
39
<< Employee::getCount() << endl;
return 0;
40 } // end main
Number of employees before instantiation of any objects is 0
Employee constructor for Susan Baker called.
Employee constructor for Robert Jones called.
Number of employees after objects are instantiated is 2
Employee 1: Susan Baker
Employee 2: Robert Jones
~Employee() called for Susan Baker
~Employee() called for Robert Jones
Number of employees after objects are deleted is 0
Fundamentals of Operator
Overloading
• Types for operator overloading
– Built in (int, char) or user-defined (classes)
– Can use existing operators with user-defined
types
• Cannot create new operators
• Overloading operators
– Create a function for the class
– Operator overloading contributes to C++’s
extensibility—one of the language’s most
appealing attributes
Overloading Stream Insertion and
Stream Extraction Operators
• << and >> operators
– Already overloaded to process each built-in
type
– Can also process a user-defined class
• Overload using global, friend functions
• Example program
– Class PhoneNumber
• Holds a telephone number
– Print out formatted number automatically
(123) 456-7890
1
// Fig. 11.3: PhoneNumber.h
2
// PhoneNumber class definition
3
#ifndef PHONENUMBER_H
4
#define PHONENUMBER_H
5
6
#include <iostream>
7
using std::ostream;
8
using std::istream;
9
10 #include <string>
11 using std::string;
12
13 class PhoneNumber
14 {
15
friend ostream &operator<<( ostream &, const PhoneNumber & );
16
friend istream &operator>>( istream &, PhoneNumber & );
17 private:
18
string areaCode; // 3-digit area code
19
string exchange; // 3-digit exchange
20
string line; // 4-digit line
21 }; // end class PhoneNumber
22
23 #endif
Notice function prototypes for overloaded operators
>> and << (must be global, friend functions)
1
// Fig. 11.4: PhoneNumber.cpp
2
// Overloaded stream insertion and stream extraction operators
3
// for class PhoneNumber.
4
#include <iomanip>
5
using std::setw;
6
7
#include "PhoneNumber.h"
Allows cout << phone; to be interpreted
as: operator<<(cout, phone);
8
9
// overloaded stream insertion operator; cannot be
10 // a member function if we would like to invoke it with
11 // cout << somePhoneNumber;
12 ostream &operator<<( ostream &output, const PhoneNumber &number )
13 {
14
15
16
output << "(" << number.areaCode << ") "
<< number.exchange << "-" << number.line;
return output; // enables cout << a << b << c;
17 } // end function operator<<
Display formatted phone number
18
19 // overloaded stream extraction operator; cannot be
20 // a member function if we would like to invoke it with
21 // cin >> somePhoneNumber;
22 istream &operator>>( istream &input, PhoneNumber &number )
23 {
24
input.ignore(); // skip (
25
input >> setw( 3 ) >> number.areaCode; // input area code
26
input.ignore( 2 ); // skip ) and space
27
input >> setw( 3 ) >> number.exchange; // input exchange
28
input.ignore(); // skip dash (-)
29
input >> setw( 4 ) >> number.line; // input line
30
return input; // enables cin >> a >> b >> c;
31 } // end function operator>>
ignore skips specified number of
characters from input (1 by default)
Input each portion of
phone number separately
1
// Fig. 11.5: fig11_05.cpp
2
// Demonstrating class PhoneNumber's overloaded stream insertion
3
// and stream extraction operators.
4
#include <iostream>
5
using std::cout;
6
using std::cin;
7
using std::endl;
8
9
#include "PhoneNumber.h"
10
11 int main()
12 {
13
PhoneNumber phone; // create object phone
14
15
cout << "Enter phone number in the form (123) 456-7890:" << endl;
16
17
// cin >> phone invokes operator>> by implicitly issuing
18
// the global function call operator>>( cin, phone )
19
cin >> phone;
20
21
cout << "The phone number entered was: ";
22
23
// cout << phone invokes operator<< by implicitly issuing
24
// the global function call operator<<( cout, phone )
25
cout << phone << endl;
26
return 0;
27 } // end main
Testing overloaded >> and <<
operators to input and output a
PhoneNumber object
Overloading Unary Operators
• Overloading unary operators
– Can overload as non-static member
function with no arguments
– Can overload as global function with one
argument
• Argument must be class object or reference to
class object
– Remember, static functions only access
static data
Overloading Unary Operators
• Overload ! to test for empty string
– If non-static member function, needs no
arguments
• class String
{
public:
bool operator!() const;
…
};
• !s becomes s.operator!()
– If global function, needs one argument
• bool operator!( const String & )
• s! becomes operator!(s)
Overloading Binary Operators
• Overloading binary operators
– Non-static member function, one argument
– Global function, two arguments
• One argument must be class object or reference
Overloading Binary Operators
• Overloading +=
– If non-static member function, needs one
argument
• class String
{
public:
const String & operator+=( const String
& );
…
};
• y += z becomes y.operator+=( z )
– If global function, needs two arguments
• const String &operator+=( String &, const
String & );
• y += z becomes operator+=( y, z )
1
// Fig. 11.6: Array.h
2
// Array class for storing arrays of integers.
3
#ifndef ARRAY_H
4
#define ARRAY_H
5
6
#include <iostream>
7
using std::ostream;
8
using std::istream;
9
10 class Array
11 {
12
friend ostream &operator<<( ostream &, const Array & );
13
friend istream &operator>>( istream &, Array & );
14 public:
15
Array( int = 10 ); // default constructor
16
Array( const Array & ); // copy constructor
17
~Array(); // destructor
18
int getSize() const; // return size
Most operators overloaded as
member functions (except << and
>>, which must be global functions)
19
20
const Array &operator=( const Array & ); // assignment operator
21
bool operator==( const Array & ) const; // equality operator
22
23
// inequality operator; returns opposite of == operator
24
bool operator!=( const Array &right ) const
25
{
26
27
Prototype for copy constructor
return ! ( *this == right ); // invokes Array::operator==
} // end function operator!=
!= operator simply returns opposite of ==
operator – only need to define the == operator
28
29
// subscript operator for non-const objects returns modifiable lvalue
30
int &operator[]( int );
31
32
// subscript operator for const objects returns rvalue
33
int operator[]( int ) const;
34 private:
35
int size; // pointer-based array size
36
int *ptr; // pointer to first element of pointer-based
37 }; // end class Array
38
39 #endif
Operators for accessing specific
array elements of Array object
1
// Fig 11.7: Array.cpp
2
// Member-function definitions for class Array
3
#include <iostream>
4
using std::cerr;
5
using std::cout;
6
using std::cin;
7
using std::endl;
8
9
#include <iomanip>
10 using std::setw;
11
12 #include <cstdlib> // exit function prototype
13 using std::exit;
14
15 #include "Array.h" // Array class definition
16
17 // default constructor for class Array (default size 10)
18 Array::Array( int arraySize )
19 {
20
size = ( arraySize > 0 ? arraySize : 10 ); // validate arraySize
21
ptr = new int[ size ]; // create space for pointer-based array
22
23
24
for ( int i = 0; i < size; i++ )
ptr[ i ] = 0; // set pointer-based array element
25 } // end Array default constructor
26
27 // copy constructor for class Array;
28 // must receive a reference to prevent infinite recursion
29 Array::Array( const Array &arrayToCopy )
30
: size( arrayToCopy.size )
31 {
32
ptr = new int[ size ]; // create space for pointer-based array
33
34
35
for ( int i = 0; i < size; i++ )
ptr[ i ] = arrayToCopy.ptr[ i ]; // copy into object
36 } // end Array copy constructor
37
38 // destructor for class Array
39 Array::~Array()
40 {
41
delete [] ptr; // release pointer-based array space
42 } // end destructor
43
44 // return number of elements of Array
45 int Array::getSize() const
46 {
47
return size; // number of elements in Array
48 } // end function getSize
We must declare a new integer array so the
objects do not point to the same memory
49
50 // overloaded assignment operator;
51 // const return avoids: ( a1 = a2 ) = a3
52 const Array &Array::operator=( const Array &right )
53 {
54
if ( &right != this ) // avoid self-assignment
55
{
56
// for Arrays of different sizes, deallocate original
57
// left-side array, then allocate new left-side array
58
if ( size != right.size )
59
{
60
delete [] ptr; // release space
61
size = right.size; // resize this object
62
ptr = new int[ size ]; // create space for array copy
63
} // end inner if
64
65
66
67
for ( int i = 0; i < size; i++ )
ptr[ i ] = right.ptr[ i ]; // copy array into object
} // end outer if
68
69
return *this; // enables x = y = z, for example
70 } // end function operator=
Want to avoid self assignment
This would be dangerous if this
is the same Array as right
71
72 // determine if two Arrays are equal and
73 // return true, otherwise return false
74 bool Array::operator==( const Array &right ) const
75 {
76
77
78
79
if ( size != right.size )
return false; // arrays of different number of elements
for ( int i = 0; i < size; i++ )
if ( ptr[ i ] != right.ptr[ i ] )
return false; // Array contents are not equal
80
81
82
83
return true; // Arrays are equal
84 } // end function operator==
85
86 // overloaded subscript operator for non-const Arrays;
87 // reference return creates a modifiable lvalue
88 int &Array::operator[]( int subscript )
89 {
90
91
// check for subscript out-of-range error
if ( subscript < 0 || subscript >= size )
92
{
93
94
95
96
integers1[ 5 ] calls
integers1.operator[]( 5 )
cerr << "\nError: Subscript " << subscript
<< " out of range" << endl;
exit( 1 ); // terminate program; subscript out of range
} // end if
97
98
return ptr[ subscript ]; // reference return
99 } // end function operator[]
100
101 // overloaded subscript operator for const Arrays
102 // const reference return creates an rvalue
103 int Array::operator[]( int subscript ) const
104 {
105
// check for subscript out-of-range error
106
if ( subscript < 0 || subscript >= size )
107
{
108
109
110
111
cerr << "\nError: Subscript " << subscript
<< " out of range" << endl;
exit( 1 ); // terminate program; subscript out of range
} // end if
112
113
return ptr[ subscript ]; // returns copy of this element
114 } // end function operator[]
115
116 // overloaded input operator for class Array;
117 // inputs values for entire Array
118 istream &operator>>( istream &input, Array &a )
119 {
120
121
for ( int i = 0; i < a.size; i++ )
input >> a.ptr[ i ];
122
123
return input; // enables cin >> x >> y;
124 } // end function
125
126 // overloaded output operator for class Array
127 ostream &operator<<( ostream &output, const Array &a )
128 {
129
int i;
130
131
// output private ptr-based array
132
for ( i = 0; i < a.size; i++ )
133
{
134
output << setw( 12 ) << a.ptr[ i ];
135
136
137
138
if ( ( i + 1 ) % 4 == 0 ) // 4 numbers per row of output
output << endl;
} // end for
139
140
141
if ( i % 4 != 0 ) // end last line of output
output << endl;
142
143
return output; // enables cout << x << y;
144 } // end function operator<<
1
// Fig. 11.8: fig11_08.cpp
2
// Array class test program.
3
#include <iostream>
4
using std::cout;
5
using std::cin;
6
using std::endl;
7
8
#include "Array.h"
9
10 int main()
11 {
12
Array integers1( 7 ); // seven-element Array
13
Array integers2; // 10-element Array by default
14
15
// print integers1 size and contents
16
cout << "Size of Array integers1 is "
Retrieve number of elements in Array
17
<< integers1.getSize()
18
<< "\nArray after initialization:\n" << integers1;
19
20
// print integers2 size and contents
21
cout << "\nSize of Array integers2 is "
22
<< integers2.getSize()
23
<< "\nArray after initialization:\n" << integers2;
24
25
// input and print integers1 and integers2
26
cout << "\nEnter 17 integers:" << endl;
27
cin >> integers1 >> integers2;
Use overloaded >> operator to input
28
29
cout << "\nAfter input, the Arrays contain:\n"
30
<< "integers1:\n" << integers1
31
<< "integers2:\n" << integers2;
Use overloaded << operator to output
32
33
// use overloaded inequality (!=) operator
34
cout << "\nEvaluating: integers1 != integers2" << endl;
35
36
37
Use overloaded != operator to test for inequality
if ( integers1 != integers2 )
cout << "integers1 and integers2 are not equal" << endl;
38
39
// create Array integers3 using integers1 as an
40
// initializer; print size and contents
41
Array integers3( integers1 ); // invokes copy constructor
42
43
cout << "\nSize of Array integers3 is "
Use copy constructor
44
<< integers3.getSize()
45
<< "\nArray after initialization:\n" << integers3;
46
47
// use overloaded assignment (=) operator
48
cout << "\nAssigning integers2 to integers1:" << endl;
49
integers1 = integers2; // note target Array is smaller
50
51
52
cout << "integers1:\n" << integers1
<< "integers2:\n" << integers2;
53
Use overloaded = operator to assign
54
// use overloaded equality (==) operator
55
cout << "\nEvaluating: integers1 == integers2" << endl;
56
57
58
if ( integers1 == integers2 )
Use overloaded == operator to test for equality
cout << "integers1 and integers2 are equal" << endl;
59
60
// use overloaded subscript operator to create rvalue
61
cout << "\nintegers1[5] is " << integers1[ 5 ];
62
63
// use overloaded subscript operator to create lvalue
64
cout << "\n\nAssigning 1000 to integers1[5]" << endl;
65
integers1[ 5 ] = 1000;
66
cout << "integers1:\n" << integers1;
Use overloaded [] operator to access
individual integers, with range-checking
67
68
// attempt to use out-of-range subscript
69
cout << "\nAttempt to assign 1000 to integers1[15]" << endl;
70
integers1[ 15 ] = 1000; // ERROR: out of range
71
return 0;
72 } // end main
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
0
0
0
0
0
0
0
3
7
4
10
14
11
15
Enter 17 integers:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
After input, the Arrays contain:
integers1:
1
2
5
6
integers2:
8
9
12
13
16
17
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
3
7
4
10
14
11
15
10
14
11
15
Evaluating: integers1 == integers2
integers1 and integers2 are equal
integers1[5] is 13
Assigning 1000 to integers1[5]
integers1:
8
9
12
1000
16
17
10
14
Attempt to assign 1000 to integers1[15]
Error: Subscript 15 out of range
11
15