Classes
Classes
Classes
#3
C++ Classes
N:1-4; D:1,3,9,10
Outline
Other issues
Initializer
Composition: Objects as members of classes
Using this pointer
Static class members
Motivation
3!!!
The resulting module structure is oriented on the operations rather than the
actual data
The defined operations specify the data to be used.
Action-oriented
concentrates on the verbs
Programmers:
Identify basic tasks to solve
problem
Implement actions to do tasks as
subprograms (procedures/
functions/subroutines)
Group subprograms into
programs/modules/libraries,
together make up a complete
system for solving the problem
Object-oriented
Programmers:
data members
Classes
Classes allow you to build smart objects that can answer many
questions (and perform various actions).
amount
source
operations getAmount()
getsource()
display()
setAmount()
setSource()
10
class ClassName
{
public:
// Declarations of public members
private:
// Declarations of private members
};
11
Designing a Class
12
Tells compiler what member functions and data members belong to the
class
13
Gradebook1.cpp (1/2)
// GradeBook class definition
class GradeBook
{
public:
// function that displays a welcome message to the
// GradeBook user
void displayMessage()
{
cout << "Welcome to the Grade Book!" << endl;
} // end function displayMessage
}; // end class GradeBook
14
Gradebook1.cpp (2/2)
// function main begins program execution
int main()
{
// create a GradeBook object named myGradeBook
GradeBook myGradeBook;
// call object's displayMessage function
myGradeBook.displayMessage();
// indicate successful termination
return 0;
} // end main
Gradebook1b.cpp
16
Local variables
17
Gradebook2.cpp (1/4)
class GradeBook
{
public:
// function that sets the course name
void setCourseName( string name )
{
Direct access to
courseName = name; // store the course name in the object
private data member
only by the same object}
// function that gets the course name
string getCourseName()
{
return courseName; // return the object's courseName
}
18
Gradebook2.cpp (2/4)
// function that displays a welcome message
void displayMessage()
{
// this statement calls getCourseName to get the
// name of the course this GradeBook represents
cout << "Welcome to the grade book for\n"
<< getCourseName() << "!" << endl;
}
Calling its own member function
private:
string courseName; // course name for this GradeBook
19
Gradebook2.cpp (3/4)
int main()
{
// string of characters to store the course name
string nameOfCourse;
// create a GradeBook object named myGradeBook
GradeBook myGradeBook;
// display initial value of courseName
cout << "Initial course name is: "
<< myGradeBook.getCourseName()
<< endl;
20
Gradebook2.cpp (4/4)
// prompt for, input and set course name
cout << "\nPlease enter the course name:" << endl;
getline( cin, nameOfCourse ); // read a course name with blanks
// set the course name
myGradeBook.setCourseName( nameOfCourse );
Modifying private data from outside the class definition with set
function
21
22
Private Access
Users cannot access and manipulate the data directly: Data hiding
23
Information hiding
Data members are declared private, thus restricting access to internal details
of the class
Methods intended for general use on the object are made public
24
26
27
For below, we have just modified private data by using the resturned
lvalue without going through boundary check!
// assign another invalid value to hour
t.badSetHour( 12 ) = 74;
To protect against the above two cases, we should return const int
&, or simply do not return a reference to a private data member
28
Constructors
The compiler will provide one when a class does not explicitly include a
constructor
Compilers default constructor only calls constructors of data members that
are objects of classes
The data members will have undefined values
One can define multiple constructors for the same class, and may
even redefine the default constructor
29
Gradebook3.cpp (1/2)
class GradeBook
{
public:
// constructor initializes courseName
// with string supplied as argument
GradeBook( string name = "default course" )
{
// call set function to initialize courseName
setCourseName( name );
No need to declare function
} // end GradeBook constructor
Gradebook3.cpp (2/2)
int main()
{
// create two GradeBook objects
GradeBook gradeBook1( "COMP104 Introduction to C++" );
GradeBook gradeBook2( "COMP152 OOP and Data Structures" );
GradeBook gradeBook3; // default
// GradeBook gradeBook4(); // does not work
class IntCell
Initializer list: used to initialize the data
{
members directly. They are NOT functions
Avoid implicit type conversion
public:
explicit IntCell( int initialValue = 0 )
: storedValue( initialValue ) {}
int read( ) const
{ return storedValue;}
void write( int x )
{ storedValue = x; }
private:
int storedValue;
}
Member functions
Indicates that the members invocation does
not change any of the data members.
Data member(s)
32
Invalid because x has to be first implicitly converted to type IntCell (by calling
IntCell(x) ) before the assignment y=x is done (i.e., doing y=IntCell(x)
implicitly).
However, if the explicit keyword is missing, the above codes would work without
compiler complaining.
33
The compiler will always find the closest match among all of
your constructor statements
Once a parameter in a constructor has a default value, all its
following parameters must have one.
class foobar{
public:
foobar( int a = 1, double d ){ // compiler complains:
// default argument missing for parameter 2
i = a; j = d;
}
private:
int i;
double j;
};
34
#include <iostream>
using namespace std;
class foo{
public:
foo( double d = 4.0 ){
i = -1;
j = d;
} // compiler will match foo f(1.2) to this
foo( int a = 10 ){
i = a;
j = -2.0;
}
// compiler will match foo f(1) to this
void print( void ) const{
cout << i << " " << j << endl;
}
private:
int i;
double j;
};
int main(){
// foo a; // compiler complains: call of overloaded `foo()' is ambiguous
// ok match to foo( int )
foo b(1);
b.print();
foo c(1.0); // ok match to foo( double )
c.print();
return 1;
}
1 -2
-1 1
35
class bar{
public:
bar( int a = 1, double d = 2.2 ){
i = a;
j = d;
}
// bar(); //if put this here, compiler complains (ambiguous constructor)
void print( void ) const{
cout << i << " " << j << endl;
}
private:
int i;
double j;
};
int main(){
bar d;
//
d.print();
bar e(2);
//
e.print();
bar f(4.5); //
f.print();
bar *bptr = new
return 1;
}
ok
ok
1 2.2
2 2.2
4 2.2
ok; a gets 4
bar [10](4, 8.0); // ok: all objects with a = 4 and d = 8.0
36
The interface lists the class and its members (data and
functions).
The implementation provides implementations of the
functions.
37
Driver files
39
Interface
Function prototypes
40
class IntCell
: storedValue ( initialValue )
public:
{ }
IntCell.h
IntCell.cpp
The interface is typically placed in a file that ends with .h. The member
functions are defined as:
ReturnType FunctionName(parameterList);
The implementation file typically ends with .cpp, .cc, or .C. The
member functions are defined as follows:
ReturnType ClassName::FunctionName(parameterList)
{ }
Scoping operator
41
Use binary scope resolution operator (::) to tie each member function
to the class definition
Client code does not need to know the implementation
42
43
Edit
Preprocess
Load
Link
Compile
Execute
Class implementation
programmer only needs to
provide header file and object
code to client
Class Libraries
Implementation file
Given .h extension
Contains data items and prototypes
Same prefix name as header file
Given .cpp extension
46
Translating a Library
Program
Source File
Program
Object File
C++
Compiler
.o
g++ -c
Library
Header File
Linker
C++
Compiler
Library
g++ -c
Implementation File
Program
Executable File
.o
Library
Object File
e.g.,
g++ foo.cpp bar.o fb.o
47
library.h
#ifndef ABC
#define ABC
int
TestInt = 99; extern int TestInt;
--------------int functionA( int );
#endif
main.cpp
#include <iostream>
#include "library.h"
using namespace std;
int TestInt=99;
int main(){
cout << "Hello"<<endl;
cout << functionA(100) << endl;
return 0;
}
source.cpp
#include "library.h"
int functionA( int i ){
return TestInt * i;
}
Output:
Hello
9900
48
Data Integrity
They should place the private data members into an appropriate state
Can return message indicating that attempts were made to assign invalid
data
50
Gradebook6.cpp
#include "GradeBook6.h" // include definition of class GradeBook
void GradeBook::setCourseName( string name )
{
// if name has 25 or fewer characters
if ( name.length() <= 25 )
courseName = name;
// if name has more than 25 characters
if ( name.length() > 25 )
{
// set courseName to first 25 characters of parameter name
courseName = name.substr( 0, 25 );
cout << "Name \"" << name << "\" exceeds maximum length
(25).\n" << "Limiting courseName to first 25 characters.";
}
}
driver6.cpp (1/2)
#include "GradeBook6.h" // include definition of class GradeBook
int main()
{
// initial course name of gradeBook1 is too long
GradeBook gradeBook1( "COMP104 Introduction to Programming in
C++" );
GradeBook gradeBook2( "COMP152 OOP and Data Structures" );
cout <<
<<
<<
<<
53
driver6.cpp (2/2)
// modify myGradeBook's courseName (with a valid-length string)
gradeBook1.setCourseName( "COMP104 C++ Programming" );
// display each GradeBook's courseName
cout << "\ngradeBook1's course name is: "
<< gradeBook1.getCourseName()
<< "\ngradeBook2's course name is: "
<< gradeBook2.getCourseName() << endl;
return 0;
}
54
55
const objects
Keyword const
Specifies that an object is not modifiable
Attempts to modify the object will result in compilation errors
56
57
class Time
{
public:
Time();
Time(unsigned initHours, unsigned initMinutes, char initAMPM);
void set(unsigned hours, unsigned minutes, char am_pm);
void display(ostream & out) const;
...
private:
unsigned myHours, myMinutes;
char myAMorPM;
// 'A' or 'P'
unsigned myMilTime;
// military time equivalent
};
58
Constructors Syntax
ClassName::ClassName (parameter_list)
: member_initializer_list
{
// body of constructor definition
}
Invoke the constructors for the data members of the object whose memory has
been allocated
Particularly important if you have reference or constant variable which has to
be initialized with a variable
The memory is allocated according to the order they are declared in the
class, while the actual construction order follows the order in the initializer list
After the member initailizers are finished , the body of the constructor is
executed
You can further change the values of the data members through some function calls
here.
59
Member Initializer
Appears between a constructors parameter list and the left brace that
begins the constructors body
Separated from the parameter list with a colon (:)
Each member initializer consists of the data member name followed by
parentheses containing the members construction and its initial value
Multiple member initializers are separated by commas
Executes before the body of the constructor executes
60
OK
class foo{
public:
foo(): i(j), m(3), k(m), j(4){
cout << i << j << k << m << endl;
}
private:
const int & i;
const int j; // ANSI C++ cannot have const int j = 4;
int & k;
int m; // ANSI C++ cannot have int m = 3;
4433
};
class foo{
public:
foo(): i(j), k(m), j(4){
m=3;
cout << i << j << k << m << endl;
}
private:
const int & i;
const int j;
int & k;
int m;
};
NOT OK
class foo{
public:
foo(): i(j), k(m){
m=3;
j = 4; // compiler complains: assignment of read-only member `foo::j'
cout << i << j << k << m << endl;
}
private:
const int & i;
const int j;
int & k;
int m;
};
61
Member Initializer
// constructor
Increment::Increment( int c, int i )
: count( c ), // initializer for non-const member
increment( i ) // required initializer for const member
{
// empty body
} // end constructor Increment
Default Constructor
Time::Time() : myHours(12), myMinutes(0),
myAMorPM('A'), myMilTime(0)
{
// void
}
mealTime
myHours
12
myMinutes
myAMorPM
myMilTime
64
Explicit-Value Constructor
Time::Time(unsigned initHours,
unsigned initMinutes,
char initAMPM)
{
set(initHours, initMinutes, initAMPM);
//a member function
}
bedTime
myHours
11
myMinutes
30
myAMorPM
myMilTime
65
Overloading Functions
Known as overloading
Compiler compares numbers and types of arguments of
overloaded functions
66
67
Default Arguments
t2
t3
t4
myHours
12
myHours
myHours
myHours
myMinutes
myMinutes
myMinutes
30
myMinutes
15
myAMorPM
myAMorPM
myAMorPM
myAMorPM
myMilTime
myMilTime
500
myMilTime
630
myMilTime
2015
68
Copy Operations
During initialization
Time t = bedTime;
During assignment
t = midnight;
bedTime
myHours
11
myHours
11
myMinutes
30
myMinutes
30
myAMorPM
myAMorPM
myMilTime
2330
myMilTime
2330
midnight
myHours
12
myHours
12
myMinutes
myMinutes
myAMorPM
myAMorPM
myMilTime
myMilTime
69
Display Functions
72
};
Friend Functions
74
Relational Operators
77
Relational Operators
In Time.cpp
bool operator<(const Time & t1, const Time & t2) {
return t1.getMilTime() < t2.getMilTime();
}
bool operator>(const Time & t1, const Time & t2) {
return t1.getMilTime() > t2.getMilTime();
}
bool operator==(const Time & t1, const Time & t2) {
return t1.getMilTime() == t2.getMilTime();
// may also be return ( !(t1 < t2) && !(t1 > t2) );
}
78
Relational Operators
In Time.cpp
bool operator<=(const Time & t1, const Time & t2) {
return t1.getMilTime() <= t2.getMilTime();
// or return !(t1 > t2);
}
bool operator>=(const Time & t1, const Time & t2) {
return t1.getMilTime() >= t2.getMilTime();
}
bool operator!=(const Time & t1, const Time & t2) {
return t1.getMilTime() != t2.getMilTime();
}
79
Operator Overloading
80
c = a + b;
81
class Complex {
...
public:
...
double real() const { return _real; }
double imag() const { return _imag; }
// No need to define any operator here!
};
//add two objects together
Complex operator +(const Complex &op1, const Complex &op2) {
double real = op1.real() + op2.real(), // cannot access private data member
imag = op1.imag() + op2.imag();
return(Complex(real, imag));
}
class Complex {
...
public:
...
friend Complex operator +(
const Complex &,
};
Complex operator +(const Complex &op1, const Complex &op2) {
83
Destructor
When functions returns; program execution leaves the scope in which that
object was instantiated
When delete is called on the object
Pointers are not traversed, and hence may have leak problem!
Destructor (Cont.)
Other Issues
Member functions declared const are not allowed to modify the object
A function is specified as const BOTH in its prototype and in its definition
Const declarations are not allowed for constructors and destructors
Const objects can only call const member functions
Therefore declare const in a function if it does not modify the object, so that a const
object can use it
Const object can access both constant and non-constant member variables
Declaring const has another advantage: if the member function is
inadvertently written to modify the object, the compiler will issue an error
message
const data members
87
#include <iostream>
using namespace std;
class foo{
public:
int i;
const int j;
foo(): j(2), i(3){}
void print( void ) const {
cout << i << endl; cout << j << endl;
}
void print2( void ) {
cout << i << endl; cout << j << endl;
}
};
int main(){
const foo f;
// f.j = 10; Compilation error
// f.i = 2;
Compilation error
cout << f.i << endl; // access non-const data member
cout << f.j << endl;
f.print();
// f.print2(); Compilation error
}
3
2
3
2
88
Note that we can have a member function which returns a reference. For example, if a
member function returns an integer reference, there are 4 possibilities.
int & bar();
This is for both constant and non-constant objects (constant object can call it only). It returns a constant
reference and hence can only be rvalue.
i = cfoo.bar(); // good; or i= ncfoo.bar();
cfoo.bar() = 10; //wrong; and nor ncfoo.bar() = 10;
This is for non-constant objects. It returns an integer reference and hence can be subsequently changed.
E.g., for a non-constant object ncfoo, we can call ncfoo.bar() = 10; or i = ncfoo.bar();
This returns a reference which can be a lvalue. However, because it can be called by a constant object
(which should never be a lvalue), this should not be used.
Either first or second for non-constant objects depending on what you want on the return value; and
The third one for constant objects
The compiler will make the call depending on whether the object is constant or not.
89
90
Employees constructor
* const first,
* const last,
&dateOfBirth,
&dateOfHire )
// initialize birthDate
initialize hireDate
Function members
*this
Data members
this
93
Access with
timePtr
timePtr->getMilTime()
myHours
12
or
myMinutes
myAMorPM
myMilTime
(*timePtr).getMilTime()
95
Static Variables
Output:
1
2
return 0;
}
96
Class-wide information
A property of the class shared by all instances, not a property of a
specific object of the class
97
Initialized by default to 0
If you want a different initial value, a static data member can be
initialized once (and only once)
Use the objects name, the dot operator and the name of the member
Example: Employee_object.count
Prefix the class name and the binary scope resolution operator (::) to the
name of the data member
Example: Employee::count
SEmployee.h
class Employee
{
public:
Employee( const char * const, const char * const );
~Employee(); // destructor
const char *getFirstName() const; // return first name
const char *getLastName() const; // return last name
// static data
static int count; // number of objects instantiated
};
100
Programmer View
class Employee
Employee::count
Employee::getCount()
object
getCount()
object
getCount()
object
getCount()
101
SEmployee.cpp (1/3)
// define and initialize static data member at file scope
int Employee::count = 0; // cannot include keyword static
// define static member function that returns number of
// Employee objects instantiated (declared static in Employee.h)
int Employee::getCount()
{
return count;
} // end static function getCount
102
SEmployee.cpp (2/3)
// constructor dynamically allocates space for first and last name
// and uses strcpy to copy first and last names into the object
Employee::Employee( const char * const first, const char * const
last )
{
firstName = new char[ strlen( first ) + 1 ]; // create space
strcpy( firstName, first ); // copy first into object
lastName = new char[ strlen( last ) + 1 ]; // create space
strcpy( lastName, last ); // copy first into object
count++; // increment static count of employees
cout << "Employee constructor for " << firstName
<< ' ' << lastName << " called." << endl;
}
SEmployee.cpp (3/3)
// destructor deallocates dynamically allocated memory
Employee::~Employee()
{
cout << "~Employee() called for " << firstName
<< ' ' << lastName << endl;
delete [] firstName; // release memory
delete [] lastName; // release memory
count--; // decrement static count of employees
} // end ~Employee destructor
104
static.cpp (1/2)
// 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
// operator new also calls the object's constructor
Employee *e1Ptr = new Employee( "Susan", "Baker" );
Employee *e2Ptr = new Employee( "Robert", "Jones" );
// call getCount on first Employee object
cout << "Number of employees after objects are instantiated is
<< e1Ptr->getCount();
Calling static member function using class name and binary scope
resolution operator
Calling a static member function through a pointer to an object
returns the value of the static variable
static.cpp (2/2)
cout << "\n\nEmployee 1: " << e1Ptr->getFirstName() << " "
<< e1Ptr->getLastName() << "\nEmployee 2: " <<
e2Ptr->getFirstName() << " " << e2Ptr->getLastName() << "\n\n";
delete e1Ptr;
e1Ptr = 0; //
delete e2Ptr;
e2Ptr = 0; //
// deallocate memory
disconnect pointer from free-store space
// deallocate memory
disconnect pointer from free-store space
106
107
108
109
Information Hiding
Data abstraction
Client cares about what functionality a class offers, not about how that
functionality is implemented
Programmers should not write code that depends on a classs
implementation details
110
111
112