0% found this document useful (0 votes)
100 views

C++ CaseStudy

This document discusses implementing an IntArray class in C++. The class represents an array of integers that handles allocation and deallocation of memory. It includes features like tracking the array size, initializing elements to non-garbage values, and deep copying arrays. The implementation covers constructors, destructors, copy constructors, assignment operators, and subscript operators to manage the array and its elements. Operator overloading is used to provide array access and assignment capabilities.

Uploaded by

alhussainraad0
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
100 views

C++ CaseStudy

This document discusses implementing an IntArray class in C++. The class represents an array of integers that handles allocation and deallocation of memory. It includes features like tracking the array size, initializing elements to non-garbage values, and deep copying arrays. The implementation covers constructors, destructors, copy constructors, assignment operators, and subscript operators to manage the array and its elements. Operator overloading is used to provide array access and assignment capabilities.

Uploaded by

alhussainraad0
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 14

Case Study

CS 201

This slide set covers pointers and


arrays in C++. You should read
Chapters 9 and 10 from your Deitel
& Deitel book.
IntArray class
● Let’s implement an IntArray class to represent an array of integers

● This class will have the following features:


○ The array knows its size
○ Array items do not have garbage values
○ It always handles allocation and deallocation (such that as a user, you do not need to worry
about explicitly using the new and delete operators)
○ It always deep copies the array items when an array’s copy is needed or the assignment
operator is applied on the array
○ The subscript operator has array bound checking for accessing the array items

2
IntArray definition
class IntArray {
public:
// If a class has dynamically allocated data members, it is highly recommended to
// re-implement the destructor and copy constructor, and overload the assignment
// operator (instead of using the ones provided by the compiler)
IntArray( const int = 0 ); // constructor with a default argument
IntArray( const IntArray& ); // copy constructor
~IntArray(); // destructor
IntArray& operator=( const IntArray& ); // overloaded assignment operator
int& operator[]( const int ); // overloaded subscript operator

private:
int size; // number of array items
int* data; // dynamically allocated array
};

3
IntArray implementation (constructor)
● Constructors are called when an // Constructor with a single integer
object is constructed (either by // parameter (this parameter has a
// default value set in the class
declaration or using the new operator) // definition such that it also serves
○ The storage class of an object determines // as a default constructor)
when it is constructed IntArray::IntArray( const int aSize ) {
if ( aSize <= 0) {
size = 0;
● It is possible to implement multiple data = nullptr;
constructors as long as their }
else {
signatures are different size = aSize;
○ The compiler selects which one to use data = new int[ size ];
based on its argument(s) for ( int i = 0; i < size; i++ )
data[ i ] = 0;
○ If an object is initialized with another object
}
of the same type at its construction, the }
compiler calls the copy constructor

4
IntArray implementation (copy constructor)
● Copy constructor is called when // This copy constructor deep copies the
○ An object is initialized with another of the // array items as opposed to default copy
same type at its declaration (construction) // constructor provided by the compiler
IntArray::IntArray( const IntArray& arr )
IntArray prev; : size( arr.size ) {
IntArray current( prev ); if ( size > 0 ) {
IntArray next = current; data = new int[ size ];
for ( int i = 0; i < size; i++ )
○ An object is passed by value as an data[ i ] = arr.data[ i ];
argument to a function (pass-by-value) }
else
○ An object is returned by value from a data = nullptr;
function (however, C++ Standard allows }
compilers to optimize this)

● If not provided explicitly, the compiler It must receive its argument by reference (not by
value). Otherwise, it results in infinite recursion.
provides a default copy constructor
Its argument should also be const to allow a
performing memberwise shallow copy
constant object to be copied and to be used only as
○ It does not deep copy the data members an rvalue inside the function.
5
IntArray implementation (destructor)
● Destructor is a special member IntArray::~IntArray() {
function that is called implicitly when if ( data )
an object is destructed (either when delete[] data;
}
its lifetime ends or when the delete
operator is used) // Constructor call for a single
○ Destructor calls are usually made in the // dynamically created object
reverse order of their corresponding IntArray* a1 = new IntArray( 400 );
constructor calls // Default constructor call for every
○ However, the storage class of objects may // object in the array
alter this order IntArray* a2 = new IntArray[ 5 ];

// Destructor call for the single object


● Each class should have only one delete a1; //
destructor (no overloading is allowed) // Every object in the array receives a
// destructor call. If "delete a2;" is
● If not provided explicitly, the compiler // used, only the first object receives
// a destructor call
creates an “empty” destructor delete[] a2; 6
Operator overloading
● For every class, the following operators are provided by the compiler
○ Assignment operator (=) → performs memberwise assignment between two objects
○ Address operator (&) → returns the address of an object

● Although they are provided by the compiler, these operators can also be
overloaded by the programmer
● Other operators can also be overloaded except . :: ?: sizeof
● Operator overloading should be done for a class individually
○ By defining a member function (in that class) for this operator
○ Where the name of this function should be operator <operator-to-be-overloaded>

7
IntArray implementation (assignment operator)
● It is called when the left operand is an object
● If not provided explicitly, the compiler provides a default assignment operator
that assigns each data member of the right object to the same data member
of the left object IntArray& IntArray::operator=( const IntArray& right ) {
if ( &right != this ) { // to avoid self-assignment
● However, this default if ( size != right.size ) {
assignment operator if ( size > 0 )
delete[] data;
performs shallow copy size = right.size;
for the memberwise if ( size > 0 )
data = new int[ size ];
assignments else
data = nullptr;
}
for ( int i = 0; i < size; i++ )
One can also define additional data[ i ] = right.data[ i ];
assignment operators where the }
right operand is of another data return *this; // to allow cascading
type }
8
this pointer
● Every object has access to its own address static member functions
● A member function can be
through a pointer called this
declared as static if it does
○ The this pointer is not a part of the object
not access any non-static
○ The compiler passes it as an implicit argument to
data member or call any
a non-static member function call of this object
non-static member function of
its class
● An object uses its this pointer
● static data members of a class
○ Implicitly when accessing its members directly
exist in memory and its static
○ Explicitly when using the this keyword
member functions can be called
even when there exist no object of
● The type of the this pointer depends on this class in memory
the object’s type and whether the executing ● A static member function
member function is declared as const does not have the this pointer

9
IntArray implementation (subscript operator)
● Other operators can also be int& IntArray::operator[]( const int ind ){
overloaded if ( ind < 0 || ind >= size )
throw out_of_range("Invalid index");
else
● This subscript operator facilitates return data[ ind ];
array bound checking for accessing }

the array items


// You can throw and catch exceptions also
// in C++, as in the following example
#include <exception>
int main(){
The return type of this function should be of a IntArray arr(100);
reference type since its returned value can be try {
used both as an lvalue and as an rvalue arr[130] = 20;
}
catch ( const exception& e ){
IntArray arr( 5 ); cout << e.what() << endl;
cout << arr[ 3 ]; // used as an rvalue }
return 0;
arr[ 3 ] = 10;// used as an lvalue
} 10
Example: Given the following Test class Test {
public:
class, what are the outputs of the Test( int i = 0 ){
following programs? id = i;
cout << "Constructor " << id << endl;
}
These examples are for you to better ~Test(){
cout << "Destructor " << id << endl;
understand when the constructor, }
copy constructor, destructor, and Test( const Test& o ){
id = o.id;
assignment operator are called. cout << "Copy const " << id << endl;
}
Test& operator=( const Test& right ){
id = right.id;
cout << "Assignment " << id << endl;
return *this;
}
int id;
};

11
Example: Given the Test class Test t1( 10 );
Test t2( 20 );
above, what are the outputs of this
void foo( bool flag ){
program? Test t3( 30 );
static Test t4( 40 );

Do not forget that the constructor, if ( flag ){


Test t5( 50 );
copy constructor, destructor, and Test t6( 60 );
assignment operator are called }
Test t7( 70 );
only for an object. For example, }
int main() {
they are not called for an object
cout << "checkpoint 1---" << endl;
pointer or a class data member Test t8( 80 );
(unless this data member is an cout << "checkpoint 2---" << endl;
foo( false );
object of another class).
cout << "checkpoint 3---" << endl;
foo( true );

cout << "checkpoint 4---" << endl;


return 0;
} 12
Example: Given the Test class int main() {

above, what are the outputs of this cout << "checkpoint 1---" << endl;
Test *b1;
program?
cout << "checkpoint 2---" << endl;
b1 = new Test ( 100 );
Do not forget that the constructor, delete b1;

cout << "checkpoint 3---" << endl;


copy constructor, destructor, and b1 = new Test [2];
assignment operator are called b1[0].id = 200;
b1[1].id = 300;
only for an object. For example, delete[] b1;
they are not called for an object cout << "checkpoint 4---" << endl;
b1 = new Test [2];
pointer or a class data member b1[0].id = 400;
(unless this data member is an b1[1].id = 500;
delete b1;
object of another class). cout << "checkpoint 5---" << endl;
return 0;
}

13
Example: Given the Test class void bar ( Test a, Test* b, Test& c ) {
// ...
above, what are the outputs of this }
int main() {
program?
cout << "checkpoint 1---" << endl;
Test t1(11);
Do not forget that the constructor, Test& t2 = t1;
Test t3 = t1;
copy constructor, destructor, and t3.id = 33;
assignment operator are called cout << "checkpoint 2---" << endl;
bar( t1, &t2, t3 );
only for an object. For example,
cout << "checkpoint 3---" << endl;
they are not called for an object Test* t4;
pointer or a class data member Test* t5;
t4 = &t1;
(unless this data member is an t5 = t4;
*t4 = t1;
object of another class).
cout << "checkpoint 4---" << endl;
bar( *t5, &t1, *t4 );

cout << "checkpoint 5---" << endl;


return 0;
} 14

You might also like