H.O.
#3
C++ Classes
N:1-4; D:1,3,9,10
Outline
Procedural vs. Object-Oriented Programming
Basic OOP
Private and public data and member functions
Accessor and mutators
Constructors
Separate compilation and conditional compilation directives to avoid
redundant declarations
Constant member functions
Operator overloading and friend
Destructors
Other issues
Initializer
Composition: Objects as members of classes
Using this pointer
Static class members
Motivation
Types such as int, double, and char are dumb objects.
They can only answer one question: What value do you
contain?
3!!!
Programming Paradigm: Procedural Concept
The main program coordinates calls to procedures in
separate modules and hands over appropriate data as
parameters
Procedural Concept - Problems
Decoupled Data and Operations
The resulting module structure is oriented on the operations rather than the
actual data
The defined operations specify the data to be used.
The design is: What data we have, and what operations we
need on manipulating it?
Object-Oriented Concept (C++)
Objects of the program interact by sending messages to each other
Procedural vs. Object Oriented
Procedural
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
Focuses on the nouns of
problem specification
Programmers:
Determine objects needed for
problem
Determine how they should work
together to solve the problem
Create types called classes with
data members
function members to operate on the
data
Instances of a type (class) are
called objects
7
Classes
Classes allow you to build smart objects that can answer many
questions (and perform various actions).
What is your temperature?
What is your temperature in Fahrenheit?
What is your humidity?
Print your temperature in Kelvin.
Objects may send messages to each other, which in turn affects
the operations of the objects. This leads to different outcomes
of the program
OOD: Object-Oriented Design
Identify the objects in the problem's specification and their
types
Identify the operations or tasks to manipulate the objects
FinancialAidAward
data
amount
source
operations getAmount()
getsource()
display()
setAmount()
setSource()
Think of them as Containers
First Look at ADTs & Implementations
For a programming task we must identify
The collection of data items
Basic operations or algorithms to be performed on them
Taken together (data items & operations) are called an
Abstract Data Type (ADT)
As an application developer, you do not need to worry how
ADT is implemented --- you only need to worry about how they
are used
ADT hence wraps implementation details from its users
10
Class Declaration Syntax
Class members are private by default, but can be declared
private
class ClassName
{
public:
// Declarations of public members
private:
// Declarations of private members
};
11
Designing a Class
Data members are normally placed in private: section of a
class
Function members usually in public: section
Can be called or manipulated by other objects
Conventionally public: section followed by private:
Can only be manipulated directly inside the class member functions
Cannot be manipulated outside the class or by other objects, which
manipulate the data through public function calls
although not required by compiler
There is also a protected: keyword
Treated as private members against access outside the class
Allow direct access to the members for the derived classes in inheritance
and polymorphism (later)
12
Example: Gradebook Class
A simple object (book) with course name
Class definition
Tells compiler what member functions and data members belong to the
class
Keyword class followed by the classs name
Class body is enclosed in braces ({})
Specifies data members and member functions
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
Access specifier public makes members available to the public
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
Use dot operator to call GradeBooks member function
Sample Output
Welcome to the Grade Book!
15
Gradebook1b.cpp
We can separate the declaration of member functions from their
definitions
Use the :: keyword
Gradebook1b.cpp
16
Variables in Classes: Local Variables and Attributes
Local variables
Variables declared in a function definitions body
When a function terminates
Cannot be used outside of that function body
The values of its local variables are lost
Attributes (data member)
Exist throughout the life of the object
Each object of class maintains its own independent copy of attributes
Represented as data members
Variables in a class definition
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
}
set function modifies private data
get function accesses private data
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
}; // end class GradeBook
Private members accessible only to member functions of the
class
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;
Accessing private data outside class definition with get function
Cannot have (Compiler yells GradeBook::courseName is
private)
cout << myGradeBook.courseName
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 );
// display message with new course name
cout << endl;
myGradeBook.displayMessage();
return 0; // indicate successful termination
} // end main
Modifying private data from outside the class definition with set
function
21
Gradebook2.cpp Sample Output
Initial course name is:
(there is nothing there)
Please enter the course name:
CS152 OOP and Date Structures
Welcome to the grade book for
CS152 OOP and Date Structures!
22
Private Access
The access-specifier private makes a data member or
member function accessible only to member functions of the
same class
private is the default access for class members
Users cannot access and manipulate the data directly: Data hiding
As a rule, data members should be declared private and
member functions should be declared public
It is appropriate to declare certain member functions private, if
they are helper functions to be accessed only by other member functions
of the same class
23
Information Hiding in C++
Two labels: public and private
Determine visibility of class members
A member that is public may be accessed by any method/function in any
class
A member that is private may only be accessed by methods in its class
A member function of a class is allowed to directly access all private
variables of an object of the same class (though it is recommended to use the
accessors or mutators to do that)
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
Software engineering with set and get functions
Public member functions that allow clients of a class to set the
values of private data members are sometimes called mutators
Public member functions that allow clients of a class to get the
values of private data members are called accessors
Using set and get functions control how clients access private
data
Can be called by functions of other classes
Should be used by other member functions of the same class (even though
the private data members can be accessed directly)
Localize the effects of changes to a classs data members by
accessing and manipulating the data members through these
get and set functions
25
Caution with Set and Get Function
Be careful when returning a reference to an object
Alias for the name of an object
Return a reference returns an acceptable lvalue that can receive a value,
i.e., may be used on the left side of an assignment statement
If a function returns a const reference, that reference cannot be used as a
modifiable lvalue
One (dangerous) way to use this return of reference: A public
member function of a class returns a reference to a private
data member of that class
Client code could alter private data
Same problem would occur if a pointer to private data were returned
26
Caution with Set and Get Function
A bad setHour function
// POOR PROGRAMMING PRACTICE:
// Returning a reference to a private data member.
class Time{
public:
int & badSetHour( int );
private:
int hour;
};
int & Time::badSetHour( int hh )
{
hour = ( hh >= 0 && hh < 24 ) ? hh : 0;
return hour; // DANGEROUS reference return
} // end function badSetHour
Boundary check: Good
private data member
27
Problems with the Above Example
Modifying a private data member through a returned reference and set it to
invalid number without going through boundary check!
Time t;
// initialize hourRef with the reference returned
int &hourRef = t.badSetHour( 20 ); // 20 is a valid hour
// use hourRef as alias to set invalid value in Time t
hourRef = 30;
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
A constructor is a special method/function that describes how an
instance of the class (called object) is constructed
Whenever an instance of the class is created, its constructor is called.
C++ provides a default constructor for each class, which is a
constructor with no input parameters (e.g., foo f;)
May be called implicitly when object is created
Must be defined in your program with the same name as the class
Cannot return values, not even void
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
prototype for calling member
functions
Constructor has the same name as class and no return type
It initializes data member
A default is supplied in case the constructor is called without
any input parameter
30
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
cout << "gradeBook1 created for course: "
<< gradeBook1.getCourseName()
<< "\ngradeBook2 created for course: "
<< gradeBook2.getCourseName()
<< "\ngradeBook3 created for course: "
<< gradeBook3.getCourseName() << endl;
return 0;
}
Creating objects explicitly by calling the constructor
Sample Output:
gradeBook1 created for course: COMP104 Introduction to C++
gradeBook2 created for course: COMP152 OOP and Data Structures
gradeBook3 created for course: default course
31
Class Definitions: Another Example
A C++ class consists of data members and methods (member functions).
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
explicit and implicit statements
main(){
int x = 4;
IntCell z(5);
IntCell t;
// same as int x(4) or int x = int(4);
// constructor: storedValue is now 5
// storedValue is now 0 (default
// constructor)
IntCell u = IntCell( x ); // us storedValue is now 4
IntCell y = x; // invalid implicit conversion: y = IntCell(x)
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
Some Words on Constructor
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
Interface and Implementation
In C++ it is more common to separate the class interface
from its implementation.
Abstract data type
The interface lists the class and its members (data and
functions).
The implementation provides implementations of the
functions.
37
Separate File for Reusability
.cpp file is known as a source-code file
Header files
Driver files
Separate files in which class definitions are placed
Allow compiler to recognize the classes when used elsewhere
Generally have .h filename extensions
Program used to test software (such as classes)
Contains a main function so it can be executed
See GradeBook4.h and Gradebook4.cpp
Same as Gradebook3.cpp, but broken into 2 files with main() in
Gradebook4.cpp
#include GradeBook4.h
38
#include preprocessor directive
#include "GradeBook.h"
Used to include header files
Quotes indicate user-defined header files
Instructs C++ preprocessor to replace directive with a copy of the
contents of the specified file
Preprocessor first looks in current directory
If the file is not found, looks in C++ Standard Library directory
Angle brackets indicate C++ Standard Library
Preprocessor looks only in C++ Standard Library directory
#include <iostream>
39
Interface
Describes what services a classs clients can use and how to
request those services
But does not reveal how the class carries out the services
A class definition that lists only member function names, return
types and parameter types
Function prototypes
A classs interface consists of the classs public member functions
(services)
40
class IntCell
IntCell::IntCell( int initialValue )
: storedValue ( initialValue )
public:
{ }
explicit IntCell( int
initialValue = 0 );
int read( ) const;
void write( int x );
private:
int storedValue;
}
IntCell.h
int IntCell::read( ) const
{ return storedValue; }
void IntCell::write( int x )
{ storedValue = x; }
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
Separating Interface from Implementation
Client code should not break if the implementation changes, as
long as the interface stays the same
Define member functions outside the class definition, in a
separate source-code file
In source-code file for a class
Implementation details are hidden
Use binary scope resolution operator (::) to tie each member function
to the class definition
Client code does not need to know the implementation
In the header file for a class
Function prototypes describe the classs public interface
42
Separating Interface from Implementation (Cont.)
Makes it easier to modify programs
Changes in the classs implementation do not affect the client as long as
the classs interface remains unchanged
Things are not quite this rosy
Header files do contain some portions of the implementation and hint
about others
private members are listed in the class definition in the header file
43
Typical C++ Development Environment
Edit
Preprocess
Link object codes with missing functions
and data
Load
Compiler translates C++ programs
into machine languages in object
codes
Link
Perform certain manipulations and file
I/O before compilation
Compile
Programmer writes program (and
stores source code on disk)
Transfer executable image to memory
Execute
Execute the program one instruction at
a time
44
The Compilation and Linking Process
Source-code file is compiled
to create the classs object
code (source-code file must
#include header file)
Class implementation
programmer only needs to
provide header file and object
code to client
Client must #include header
file in their own code
So compiler can ensure that the
main function creates and
manipulates objects of the class
correctly
45
Class Libraries
Class declarations placed in header file
Implementation file
Given .h extension
Contains data items and prototypes
Same prefix name as header file
Given .cpp extension
Programs which use this class library called client programs
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;
}
> g++ main.cpp source.cpp
ld: fatal: symbol `TestInt' is multiply-defined:
(file /var/tmp/ccvkmxE2.o type=OBJT; file /var/tmp/ccgj1SDu.o
type=OBJT);
ld: fatal: File processing errors. No output written to a.out
collect2: ld returned 1 exit status
Output:
Hello
9900
48
Why #ifndefine #define #endif Statement?
It is ok to have multiple declarations of a function prototype, but not
for its definition
In creating the .o file, there may be nested #include statement
The nested #include statement may be recursive
In the .h file, put the prototypes there
.h files are likely to be multiply-included
In main.cpp, #include foo.h
In foo.h, #include bar.h
In bar.h, #include foo.h
To break the infinite recursive inclusion, use #ifndefine #define to
define a variable in the compilation process of .o file
If a variable has been defined, the compiler will skip the code
segment between #ifndefine and #endif.
49
Data Integrity
Data integrity are not automatic by putting data members as
private
Member functions that set the values of private data should
verify that the intended new values are proper
The programmer must provide appropriate validity checking and report
the errors
They should place the private data members into an appropriate state
set functions can be used to validate data besides simply setting
the value
Known as validity checking
Keeps object in a consistent state
The data member contains a valid value
Can return message indicating that attempts were made to assign invalid
data
50
Gradebook6.h (with Validity Checking)
#ifndef GRADEBOOK_H
#define GRADEBOOK_H
// GradeBook class definition
class GradeBook
{
public:
GradeBook( string );
void setCourseName( string );
string getCourseName();
void displayMessage();
private:
string courseName;
};
#endif
Same as Gradebook4.h, but with the interface, implementation and driver
separated into three files
Interface contains data members and member function prototypes only
Note the #ifndef statements to prevent multiple inclusions
51
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.";
}
}
set functions perform validity checking to keep courseName in a consistent
state
GradeBook implementation is placed in a separate file
Include the header file to access the class name GradeBook
Binary scope resolution operator :: ties a function to its class
52
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 <<
<<
<<
<<
"gradeBook1's initial course name is: "
gradeBook1.getCourseName()
"\ngradeBook2's initial course name is: "
gradeBook2.getCourseName() << endl;
Include the header file to use the class GradeBook
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;
}
Call set function to perform validity checking directly
In Linux, compile them all together using
g++ Gradebook6.cpp driver6.cpp
Or using object files:
g++ -c Gradebook6.cpp; g++ -c driver6.cpp; g++
driver6.o driver6.o
54
driver6.cpp Sample Output
Name "COMP104 Introduction to Programming in C++" exceeds maximum
length (25).
Limiting courseName to first 25 characters.
gradeBook1's initial course name is: COMP104 Introduction to P
gradeBook2's initial course name is: COMP152 OOP and Data Stru
gradeBook1's course name is: COMP104 C++ Programming
gradeBook2's course name is: COMP152 OOP and Data Stru
55
Constant Object and Member Functions
Principle of least privilege
One of the most fundamental principles of good software engineering
Applies to objects, too
const objects
Keyword const
Specifies that an object is not modifiable
Attempts to modify the object will result in compilation errors
56
Const member functions
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
For a const object, only its const member function can be called
Because all the other functions may modify its value
const declarations are not allowed for constructors and
destructors
Because by definition they modify the object
57
Another Example: Time Class
Information hiding (Time.h and Time.cpp)
Two types of constructors
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
}
Member initializer list
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
Required for initializing
Data members that are references
const data members
Member initializer list
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
Initializer to Initialize Variables on Its Construction
OK
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
Another Example on Member Initializer
class Increment
{
public:
Increment( int c = 0, int i = 1 ); // default constructor
// function addIncrement definition
void addIncrement()
{
count += increment;
} // end function addIncrement
void print() const; // prints count and increment
private:
int count;
const int increment; // const data member
};
const data member increment must be initialized using a
member initializer
62
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
Colon (:) marks the start of a member initializer list
c is the initial count, increment is the increment step
Member initializer for non-const member count
Required member initializer for const member increment
Not providing a member initializer for a const data member is
a compilation error
See Increment.h, Increment.cpp and const2.cpp
63
Default Constructor
Time::Time() : myHours(12), myMinutes(0),
myAMorPM('A'), myMilTime(0)
{
// void
}
Time mealTime = Time();
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
}
Time bedTime = Time(11,30,P);
bedTime
myHours
11
myMinutes
30
myAMorPM
myMilTime
2330 (a random value if myMilTime is not set in set())
65
Overloading Functions
Note existence of multiple functions with the same name
Time();
Time(unsigned initHours,
unsigned initMinutes,
char initAMPM);
Known as overloading
Compiler compares numbers and types of arguments of
overloaded functions
Checks the "signature" of the functions
66
Constructors with Default Arguments
Constructors can specify default arguments
Can initialize data members to a consistent state
Even if no values are provided in a constructor call
Constructor that defaults all its arguments is also a default constructor
Can be invoked with no arguments
Maximum of one default constructor per class
67
Default Arguments
Possible to specify default values for constructor arguments
Time(unsigned initHours = 12,
unsigned initMinutes = 0,
char initAMPM = 'A');
Time t1, t2(5), t3(6,30), t4(8,15,'P');
t1
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
Other Class Operations
Accessors: "get" functions
unsigned Time::getMinutes() const {
return myMinutes;
}
unsigned Time::getHours() const {
return myHours;
}
unsigned Time::getAMPM() const {
return myAMorPM;
}
unsigned Time::getMilTime() const {
return myMilTime;
}
70
Other Class Operations
Mutators: "set" functions
void Time::set(unsigned hours, unsigned minutes, char
am_pm)
{
// Check class invariant
if (hours >= 1 && hours <= 12 &&
minutes >= 0 && minutes <= 59 &&
(am_pm == 'A' || am_pm == 'P'))
{
myHours = hours;
myMinutes = minutes;
myAMorPM = am_pm;
myMilTime = toMilitary(hours, minutes, am_pm);
}
else
cerr << "*** Can't set time with these values
***\n";
}
71
Display Functions
Two functions used for output
display() inside the class as member function
operator<<() outside the class as an external function
The display function:
void Time::display(ostream & out) const
{
out << myHours << ':'
<< (myMinutes < 10 ? "0" : "") << myMinutes
<< ' ' << myAMorPM << ".M. ("
<< myMilTime << " mil. time)";
}
But how about the operator << ?
72
Implementing Output by Overloading <<
Use the public display() function to display the object
Declaration in .h file
class Time {
};
ostream & operator<<(ostream & out, const Time & t);
Definition in .cpp file
ostream & operator<<(ostream & out, const Time & t)
{
t.display(out);
return out;
}
73
Friend Functions
Possible to specify operator<<() as a "friend" function
Thus give "permission" to access private data elements directly
Declaration in .h file (but not inside class)
class Time {
friend ostream & operator<<(ostream & out, const
Time & t);
};
74
Friend Functions (Cont.)
Definition in .cpp file
ostream & operator<<(ostream &out, const Time &t)
{
out << t.myHours<<":"
<< (t.myMinutes< 10? "0": "") //print,e.g., 05
<< t.myMinutes
<< ' '<<t.myAMorPM<<".M.";
return out;
}
cout << t is converted to operator<<(cout, t)
Note that the function can directly access private data members without
going through accessor functions
Remember to return ostream as a reference as we require it to be used in
cascade
A friend function is NOT a member function
not qualified with class name and ::
receives class object on which it operates as a parameter
75
Advance Member Function
Advances itself by adding to myHours, myMinutes
void Time::advance(unsigned hours, unsigned minutes)
{
// Increment the myMilTime member
myMilTime += 100 * hours + minutes;
// Adjust to proper format
unsigned milHours = myMilTime / 100,
milMins = myMilTime % 100;
milHours += milMins / 60;
milMins %= 60;
milHours %= 24;
myMilTime = 100 * milHours + milMins;
// Now set the standard time data members
toStandard(myMilTime, myHours, myMinutes, myAMorPM);
}
76
Relational Operators
Time object compares itself with another
In Time.h, we show the implementation of operator overloading
for two Time objects (more on that in later handout):
bool operator<(const Time & t1, const Time & t2);
bool operator>(const Time & t1, const Time & t2);
bool operator==(const Time & t1, const Time & t2);
bool operator<=(const Time & t1, const Time & t2);
bool operator>=(const Time & t1, const Time & t2);
bool operator!=(const Time & t1, const Time & t2);
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
As an external function (external view)
As a friend of an external function
Has to use accessors and mutators to get or set variables
Discussed in Time.h
Can directly access data members
Discussed just now in the slides
As a member function (internal view of the object)
Can directly access data members
80
Internal Function: Operator Overloading for a
Complex Class
class Complex {
...
public:
self
...
Complex operator +(const Complex &op) {
double real = _real + op._real,
imag = _imag + op._imag;
return(Complex(real, imag)); //construct a Complex object
}
...
};
An expression of the form
c = a + b;
is translated into a method call
c = a.operator +(b);
We need to return the result in a complex object so that we can compute
a+b+c
We have made the operator + a member of class Complex. This is an
internal view of the object (the object is added to op), which differs from the
external declaration of adding two objects to be discussed next: Complex
operator+(const Complex &a, const Complex &b);
81
External Function: Operator Overloading for
Complex Objects
The overloaded operator may not be a member of a class: It can rather be
defined outside the class as a normal overloaded function. For example, we could
define operator +, which takes two arguments, in this way:
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));
}
A call of a+b is then converted to operator+(a,b)
82
Friend for Complex Objects
We can define functions or classes to be friends of a class to
allow them direct access to its private data members
class Complex {
...
public:
...
friend Complex operator +(
const Complex &,
const Complex &
);
// NOT member function
};
Complex operator +(const Complex &op1, const Complex &op2) {
double real = op1._real + op2._real,
//access private data members due to friend
imag = op1._imag + op2._imag;
return(Complex(real, imag));
}
83
Destructor
C++ destroys an object when it goes out of scope; called
implicitly when an object is destroyed
A special member function
Name is the tilde character (~) followed by the class name, e.g.,
~Time()
The default destructor is to free up all the private members
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!
To declare a destructor, use a member function which has no
return and no parameters: ~foo();
84
Destructor (Cont.)
C++ provides a default destructor for each class
A C++ class can have only one destructor
Destructor overloading is not allowed
Receives no parameters and returns no value
If the programmer does not explicitly provide a destructor, the
compiler creates an empty destructor
The default simply applies the destructor on each data member.
We can redefine the destructor of a class.
May not specify a return typenot even void
It is a syntax error to attempt to
pass arguments to a destructor
specify a return type for a destructor (even void cannot be specified)
return values from a destructor
overload a destructor
85
Other Issues
Constant Object and Constant Member Functions
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
It is an error to modify a const data member
Prevents accidental changes to a data member in any member functions
Must be initialized with a member initializer
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
A Member Function Returning a Reference
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();
const 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;
int & bar() const;
This is for non-constant objects. It has to be a rvalue.
i = ncfoo.bar(); // good
ncfoo.bar() = 10; // wrong: compilation error
const int & bar() const;
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.
In a program, therefore, you can have
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
Composition: Objects as Members of Classes
Sometimes referred to as a has-a relationship
A class can have objects of other classes as members
Example: AlarmClock object with a Time object as a member
Initializing member objects
Member initializers pass arguments from the objects constructor to
member-object constructors
Before the enclosing class object (host object) is constructed
If a member initializer is not provided, the member objects default
constructor will be called implicitly
Example: Date.h, Date.cpp, Employee.h, Employee.cpp and
composition.cpp
90
Composition: Objects as Members of Classes (Cont.)
Date.h, Date.cpp, Employee.h, Employee.cpp, etc.
Employee has two const objects of class Date as members
class Employee
{
public:
Employee( const char * const, const char * const,
const Date &, const Date & );
void print() const;
~Employee(); // provided to confirm destruction order
private:
char firstName[ 25 ];
char lastName[ 25 ];
const Date birthDate; // composition: member object
const Date hireDate; // composition: member object
};
Constructor of Employee takes parameters to be passed to the
constructor of class Date via member initializers
91
Composition: Objects as Members of Classes
Employees constructor
Employee::Employee( const char
const char
const Date
const Date
: birthDate( dateOfBirth ),
hireDate( dateOfHire ) //
{
...
* const first,
* const last,
&dateOfBirth,
&dateOfHire )
// initialize birthDate
initialize hireDate
Member initializers pass arguments to Dates implicit copy
constructor (equivalent to const Date birthDate =
dateOfBirth;)
A compilation error occurs if a const member object is not
initialized with a member initializer in the constructor
92
The this Pointer
Every class has a keyword, this
a pointer whose value is the address of the object
Value of *this would be the object itself
Class Object
Function members
*this
Data members
this
93
Using the this Pointer
Every object has access to its own address through a pointer
called this (a C++ keyword)
Objects use the this pointer implicitly or explicitly
Implicitly when accessing members directly
Explicitly when using keyword this
Type of the this pointer (i.e., whether it can be modified or not)
depends on the type of the object and whether the executing member
function is declared const
Usually used when you want to return the modified object:
foo & foo::bar(){
// manipulate and transform data members
//
return *this;
}
94
Pointers to Class Objects
Possible to declare pointers to class objects
Time * timePtr = &t;
Time * timePtr = new Time( 12, 0, A, 0 );
Access with
timePtr
timePtr->getMilTime()
myHours
12
or
myMinutes
myAMorPM
myMilTime
(*timePtr).getMilTime()
Call delete to free the memory
delete timePtr; // call destructor
95
Static Variables
Static variables are put somewhere in memory
Ct can only be accessed within the function but it is not deleted
with the function
int bar( void ){
static int ct = 0;
ct++;
return ct;
}
int main(){
cout << bar() << endl;
cout << bar() << endl;
Output:
1
2
return 0;
}
96
Static Class Members
Only one copy of a variable shared by all objects of a class
Class-wide information
A property of the class shared by all instances, not a property of a
specific object of the class
Declaration begins with keyword static
May seem like global variables but they have class scope
Outside the class, they cannot be accessed
97
Static Class Members
Can be declared public, private or protected
Primitive (Fundamental-type) static data members
A const static data member of int or enum type can be
initialized in its declaration in the class definition
Initialized by default to 0
If you want a different initial value, a static data member can be
initialized once (and only once)
Alternatively, you can also initialize it in file scope
All other static data members must be defined at file scope
(i.e., outside the body of the class definition)
static data members of class types (i.e., static member objects)
that have default constructors need not be initialized because
their default constructors will be called
98
Static Class Members
Exists even when no objects of the class exists
To access a public static class member when no objects of the
class exist:
Also accessible through any object of that class
Use the objects name, the dot operator and the name of the member
Example: Employee_object.count
static member function
Prefix the class name and the binary scope resolution operator (::) to the
name of the data member
Example: Employee::count
Is a service of the class, not of the object of the class
Example: SEmployee.h, SEmployee.cpp, static.cpp
99
SEmployee.h
Employee has a static function and a static data member
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 member function
static int getCount(); // return number of objects instantiated
private:
static data member keeps track of number
char *firstName;
of Employee objects that currently exist;
char *lastName;
static member function may be called even
the object does not exist
// 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
static data member is defined and initialized at file scope in the
.cpp file
static member function can access only static data, because the
function might be called when no objects exists
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;
}
Non-static member function (e.g., constructor) can modify the
classs static data members
103
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
Remember to deallocate memory reserved for arrays
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
Same as getting the value of Employee::count or calling
Employee::getCount()
105
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
// no objects exist, so call static member function getCount again
// using the class name and the binary scope resolution operator
cout << "Number of employees after objects are deleted is "
<< Employee::getCount() << endl;
Even when no object exists, we can still call static member
function getCount()
106
static.cpp Sample Output
Number of employees before instantiation of any objects is 0
Employee constructor for Susan Baker called.
Employee constructor for Robert Jones called.
Number of employees after objects are instantiated is 2 (same as
calling Employee::getCount() = 2)
Employee 1: Susan Baker
Employee 2: Robert Jones
~Employee() called for Susan Baker
~Employee() called for Robert Jones
Number of employees after objects are deleted is 0
107
Constant Static Variable
#include <iostream>
using namespace std;
class foo{
public:
static int getcount();
// static member function cannot have `const' method qualifier
private:
const static int count;
};
// initialization of constant static variable: must be here; not in main()
const int foo::count = 2;
int foo::getcount(){
cout << count;
}
int main(){
foo::getcount(); // print out 2
foo::getcount(); // print out 2
cout << foo::count; // wrong as 'const int foo::count' is private
return 0;
}
108
Static Class Members (Summary)
Declare a member function static
It cannot access non-static data members or non-static member functions of
the class (because the object may not exist when the function is called)
A static member function does not have a this pointer
static data members and static member functions exist independently of
any objects of a class, i.e., when a static member function is called, there
might not be any objects of its class in memory
109
Data Abstraction and Information Hiding
Information Hiding
A class normally hides implementation details from clients
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
Abstract Data Types (ADTs)
Essentially ways of representing real-world notions to some
satisfactory level of precision within a computer system
Types like int, double, char and others are all ADTs
Capture two notions:
e.g., int is an abstract representation of an integer
Data representation
Operations that can be performed on the data
C++ classes implement ADTs and their services
111
Example: Array Abstract Data Type
Many array operations not built into C++
Programmers can develop an array ADT as a class that is
preferable to raw arrays
e.g., subscript range checking
Can provide many helpful new capabilities
C++ Standard Library class template vector
112