C++ CaseStudy
C++ CaseStudy
CS 201
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 ];
● 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 }
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 );
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;
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 );