CSE 230 - C++ Notes 3 Classes and Data Abstraction - Part II Constant Objects
CSE 230 - C++ Notes 3 Classes and Data Abstraction - Part II Constant Objects
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
#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
#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
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
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