You are on page 1of 10

CSE 230 - C++ Notes 3

Classes and Data Abstraction – Part II

Constant Objects
•The principle of “least privilege” can be applied to objects that are not
modifiable.
•The keyword ________ may be used to indicate that an object will not be
modified after it is initialized.
•Example:
const Time noon(12, 0, 0);
•C++ disallow any member function calls for ________ objects unless the
functions themselves are declared const. This includes the get functions as
well.
•A function is specified both in its prototype and in its definition by
inserting const after the parameter list.
•Example:
int Time::getHour() const {return hour;}
Constant Objects(cont’d)
•An interesting problem arises for constructors and destructors, each of
which often needs to modify objects.
•A constructor must be allowed to modify an object so that the object can be
initialized properly. It can also call ___________ functions to initialize a
________ object.
•A destructor must be able to perform its termination housekeeping chores
before an object is destroyed.
•The _______ declaration is not allowed for constructors and destructors.

#ifndef TIME5_H
#define TIME5_H
class Time {
public:
Time( int = 0, int = 0, int = 0 ); // default constructor – can’t be declared as a const
void setTime( int, int, int ); /* set functions */
void setHour( int );
void setMinute( int );
void setSecond( int );
int getHour() const; /* get functions (normally declared const)*/
int getMinute() const;
int getSecond() const;
void printMilitary() const; /* prints functions(normally declared const) */
void printStandard(); // should be const

1
private:
int hour;
int minute;
int second;
}; // end class Time (interface)
#endif
#include <iostream>
using std::cout;
#include "time5.h"
Time::Time( int hr, int min, int sec ) { setTime( hr, min, sec ); }
void Time::setTime(int h, int m, int s ) // non-const
{
setHour( h );
setMinute( m );
setSecond( s );
} // end function setTime
void Time::setHour( int h ) { hour = ( h >= 0 && h < 24 ) ? h : 0; }
void Time::setMinute( int m ){ minute = (m>=0 && m<60 ) ? m : 0;}
void Time::setSecond( int s ) { second = ( s >= 0 && s < 60 ) ? s : 0;}
int Time::getHour() _______ { return hour; }
int Time::getMinute() _______ { return minute; }
int Time::getSecond() _______ { return second; }
// Display military format time: HH:MM
void Time::printMilitary() const
{
cout << ( hour < 10 ? "0" : "" ) << hour << ":"
<< ( minute < 10 ? "0" : "" ) << minute;
} // end function printMilitary
// Display standard format time: HH:MM:SS AM (or PM)
void Time::printStandard() // should be const
{
cout << ( ( hour == 12 ) ? 12 : hour % 12 ) << ":"
<< ( minute < 10 ? "0" : "" ) << minute << ":"
<< ( second < 10 ? "0" : "" ) << second
<< ( hour < 12 ? " AM" : " PM" );
} // end function printStandard
// end class Time (implementation)
#include "time5.h"
int main()
{
Time wakeUp( 6, 45, 0 ); //non-const object
const Time noon( 12, 0, 0 );//const object calls non-const constructor
// MEMBER FUNCTION OBJECT
wakeUp.setHour( 18 ); // non-const _________
noon.setHour( 12 ); // non-const const*
wakeUp.getHour(); // const _________
noon.getMinute(); // const const

2
noon.printMilitary(); // const const
noon.printStandard(); // non-const const*
return 0;
} // end function main
* Depending on the compiler, an error or warning message is issued.
Constant Data Members
•A member_____________ is used to initialize a private data member.
•The format is as follows:
className::constructorName (parameter list)
: privateDataName( value )
{ other statements }
•For example:
Increment::Increment(int c, int i)
: increment( i )
{ count = c;}
•All data members (including non-const) can be initialized using member __________.
For multiple initializations, include them in a comma-separated list after the colon.
•For example:
Increment::Increment(int c, int i) : increment( ____ ), count(_____ ) { }
#include <iostream>
using std::cout;
using std::endl;
class Increment {
public:
Increment( int c = 0, int i = 1 );
void addIncrement() { count += increment; }
void print() const;
private:
int count;
const int increment; // const data member – not necessary to initialize
}; // end class Increment
Increment::Increment( int c, int i ) : increment( i ) // initializer for const member
{ count = c; } // increment = i; is a syntax error
void Increment::print() __________
{
cout << "count = " << count
<< ", increment = " << increment << endl;
} // end function print
int main()
{
Increment value( 10, 5 );
cout << "Before incrementing: ";
value.print();
for ( int j = 0; j < 3; j++ ) {
value.addIncrement();
cout << "After increment " << j + 1 << ": ";
value.print();
} // end for
return 0;

3
} // end function main
Before incrementing: count = ______, increment = 5
After increment 1: count = ______, increment = 5
After increment 2: count = ______, increment = 5
After increment 3: count = ______, increment = 5

Composition of Objects (HAS-A)


•A class can have objects of other classes as members.
•Whenever an object is created, its constructor is called, so we need to specify how
arguments are passed to member-objects constructors.
•Member objects are constructed in the order in which they are declared (not in the order
they are listed in the constructor’s initializer list).
•Objects are constructed from the inside out and destructed in the reverse order.

#ifndef DATE_H
#define DATE_H
class Date {
public:
Date( int = 1, int = 1, int = 1900 ); // default constructor
void print() const; // print date in month/day/year format
~Date(); // confirm destruction order
private:
int month; // 1-12
int day; // 1-31 based on month
int year; // any year
int checkDay( int ); // utility function to test proper day for month and year
}; // end class Date (interface)
#endif
#include <iostream>
using std::cout;
using std::endl;
#include "date.h"
Date::Date( int mn, int dy, int yr )
{
if ( mn > 0 && mn <= 12 ) // validate the month
month = mn;
else {
month = 1;
cout << "Month " << mn << " invalid. Set to month 1.\n";
} // end else
year = yr; // should validate yr
day = checkDay( dy ); // validate the day
cout << "Date object constructor for date ";
print(); // print with no arguments
cout << endl;
} // end Date constructor
void Date::print() const { cout << month << '/' << day << '/' << year; }
Date::~Date() // Destructor: provided to confirm destruction order
{
cout << "Date object destructor for date ";

4
print(); cout << endl;
} // end Date destructor

int Date::checkDay( int testDay ) // test for proper day value


{
static const int daysPerMonth[ __13__ ] =
{__0__, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
if ( testDay > _0____ && testDay <= _daysPerMonth___________[ _month______ ] )
return testDay;
if ( month == __2___ && testDay == ___29____ && // February: Check for leap year
( year % 400 == 0 ||
( year % 4 == 0 && year % 100 != 0 ) ) )
return testDay;
cout << "Day " << testDay << " invalid. Set to day 1.\n";
return 1; // leave object in consistent state if bad value
} // end function checkDay
// end class Date (implementation)

#ifndef EMPLOYEE _H
#define EMPLOYEE _H
#include "date.h"
class Employee {
public:
Employee( char *, char *, int, int, int, int, int, int );
void print() const;
~Employee(); // provided to confirm destruction order
private:
char firstName[ 25 ]; // fixed size up to 25 characters
char lastName[ 25 ];
const Date birthDate;
const Date hireDate;
}; // end class Employee (interface)
#include <iostream>
using std::cout;
using std::endl;
#include <cstring>
#include "employee.h"
#include "date.h"
Employee::Employee( char *fname, char *lname, int bmonth, int bday, int byear,
int hmonth, int hday, int hyear )
: birthDate( bmonth, bday, byear ), hireDate( hmonth, hday, hyear )
{
int length = strlen( fname ); // copy fname
length = ( length < 25 ? length : 24 );// into firstName
strncpy( firstName, fname, length ); // and be sure
firstName[ length ] = '\0'; // that it fits
length = strlen( lname ); // copy lname
length = ( length < 25 ? length : 24 );// into lastName
strncpy( lastName, lname, length ); // and be sure
lastName[ length ] = '\0'; // that it fits
cout << "Employee object constructor: " << firstName << ' ' << lastName << endl;
} // end Employee constructor
void Employee::print() const
{
cout << lastName << ", " << firstName << "\nHired: ";

5
hireDate.print();
cout << " Birth date: ";
birthDate.print();
cout << endl;
} // end function print
// Destructor: provided to confirm destruction order
Employee::~Employee()
{
cout << "Employee object destructor: "
<< lastName << ", " << firstName << endl;
} // end Employee destructor
// end class Employee (implementation)

#include <iostream>
using std::cout;
using std::endl;
#include " employee.h"
int main()
{
Employee e( "Bob", "Jones", 7, 24, 1949, 3, 12, 1988 );
cout << '\n';
e.print();
cout << "\nTest Date constructor with invalid values:\n";
Date d( 14, 35, 1994 ); // invalid Date values
cout << endl; // this can be done by creating another function
return 0;
} // end function main

Order of constructions and destructions:

Date object constructor for date _7__/_24__/_1949___


Date object constructor for date _3__/_12__/_1988___
Employee object constructor for : Bob Jones

Date object constructor for invalid date. Set to 1/1/1994

Date object destructor for date /1/1994


Employee object destructor for : Bob Jones
Date object destructor for date __3__/_12__/_1988____
Date object destructor for date __7__/_24__/__1949___

Friend Functions and Classes


•A friend function of a class is defined outside that class’s scope, yet has the right to
access __private_______ members of the class.
•A function or an entire class may be declared to be a friend of another class.
•Using friend functions can enhance performance and it is often appropriate when a
member function can not be used for certain operations.
•To declare a friend function, precede the function prototype with the keyword
friend.

6
•To declare classTwo as a friend of classOne, place a declaration of the following
form in the definition of classOne:
friend class classTwo;
•Friendship is granted (not taken) and is neither symmetric nor transitive.

#include <iostream>
using std::cout;
using std::endl;
class Count {
friend void setData( Count &, int ); // friend declaration
public:
Count() { data = 0; } // constructor
void print() const { cout << data << endl; }
private:
int data;
}; // end class Count
void setData( Count &c, int val ) {
c.data = val; // legal: setData is a friend of Count
} // end function setX
int main()
{
Count counter;
cout << "counter.data after instantiation: ";
counter.print();
cout<<"counter.data after call to setData friend function:";
setData( counter, 8 ); // set data with a friend
counter.print();
return 0;
} // end function main
Using this
•Every object has access to its own address through a pointer called this.
•An object’s this pointer is _not_____ part of the object (has no effect in the
_size_____). Rather, this is passed into the object (by the compiler) as an implicit
first argument on every non-__static______ member function.
•The this pointer is implicitly used to reference both the data members and member
functions of an object. It can also be used explicitly.
•The type of the this pointer depends on type of object.
•Example:
Employee * const (const pointer to an object)
const Employee * const (const pointer to an object that is constant)

7
#include <iostream>
using std::cout;
using std::endl;
class Test {
public:
Test( int = 0 ); // default constructor
void print() const;
private:
int data;
}; // end class Test
Test::Test( int a ) { data = a; } // constructor
void Test::print() const { // ( ) around *this required
cout << data << this->data << (*this ).data << endl;
} // end function print
int main()
{
Test testObject( 12 );
testObject.print();
return 0;
} // end function main

Dynamic Memory Allocation


•In C:
TypeName *typeNamePtr;
typeNamePtr = malloc( sizeof(TypeName) );
•In C++ use _____ typeName to create a new space:
double *somePtr = ______ double(3.14);
int *arrayPtr = ______ int[10];
char *str = _______ char[20];
•Use ________ typeName to destroy an allocated space:
_______ somePtr;
_______ [ ] arrayPtr; // [ ] must be used for arrays
•new and delete automatically call the class constructor and destructor
respectively.
Static Class Members
•Each object of a class has its own copy of all the data members of the class.
•A static class variable is shared by all objects of a class and it represents “class-wide”
information (i.e. a property of the class, not of a specific object).
•A static data member must be initialized once at file scope.
•Although static data members may seem like global variables, but they have class
scope.
•A static member function has no ________ pointer and referring to it is a syntax
error. Also, it can’t be a __________.
• The member function may be declared static if it does not access non-static class
data members and member functions.
#ifndef EMPLOYEE_H
#define EMPLOYEE_H

8
class Employee {
public:
Employee( const char*, const char* ); // constructor
~Employee(); // destructor
const char *getFirstName() const; // return first name
const char *getLastName() const; // return last name
// static member function
static int getCount(); // return # objects instantiated
private:
char *firstName;
char *lastName;
// static data member
static int count; // number of objects instantiated
}; // end class Employee (interface)
#endif
#include <iostream>
using std::cout;
using std::endl;
#include <cstring>
#include <cassert>
#include "employee.h"
int Employee::count = 0; // Initialize the static data member
int Employee::getCount() { return count; } // static member function
Employee::Employee( const char *first, const char *last )
{
firstName = ________ char[ strlen( first ) + 1 ];
assert( firstName != 0 ); // ensure memory allocated
strcpy( firstName, first );
lastName = ________ char[ strlen( last ) + 1 ];
assert( lastName != 0 ); // ensure memory allocated
strcpy( lastName, last );
++count; // increment static count of employees
cout<<"Employee constructor for " << firstName<< ' ' << lastName << " called.\n“
} // end Employee constructor
// Destructor deallocates dynamically allocated memory
Employee::~Employee()
{
cout << "~Employee() called for " << firstName << ' ' << lastName << endl;
_________ [ ] firstName; // recapture memory
_________ [ ] lastName; // recapture memory
--count; // decrement static count of employees
} // end Employee destructor
const char *Employee::getFirstName() const
{
// Const before return type prevents client from modifying
// private data. Client should copy returned string before
// destructor deletes storage to prevent undefined pointer.
return firstName;
} // end function getFirstName
const char *Employee::getLastName() const
{
return lastName;
} // end function getLastName
// end class Employee (implementation)

9
#include <iostream>
using std::cout;
using std::endl;
#include "employee.h"
int main()
{ // class name
cout << “# of employees before instantiation is"<< Employee::getCount() << endl;
Employee *e1Ptr = new Employee( "Susan", "Baker" );
Employee *e2Ptr = _______ Employee( "Robert", "Jones" );
cout << “#of employees after instantiation is" << e1Ptr->getCount();
cout <<"\nEmployee 1:"<<e1Ptr->getFirstName()<<" "<< e1Ptr->getLastName()
<<"\nEmployee 2:" <<e2Ptr->getFirstName()<<" "<<e2Ptr->getLastName();
<<“\n\n”;
________ e1Ptr; // recapture memory
e1Ptr = 0; // disconnect e1Ptr from the previously allocated space
________ e2Ptr; // recapture memory
e2Ptr = 0; // class name
cout<<"Number of employees after deletion is"<< Employee::getCount() << endl;
return 0;
} // end function main

10

You might also like