Classes 2

advertisement
Classes: Part 2 
Static vs. Dynamic Variables
Generally speaking: ‘static’ is meant to be ‘non-dynamic’
 Global and local variables
 Locals are automatic variables from the ‘stack’ of the memory,
therefore called ‘static’
 Dynamic variables are from the ‘heap’ of the memory.
In C and C++, ‘static’ is well defined:
 ‘static’ variables are ‘global’ with the file scope
2
Static Variables in C and C++
 Static variables are put somewhere ‘permanently’ or ‘globally’ in
memory
 The static variable ‘s’ can only be accessed within the function but it is
not deleted with the function
 A ‘local’ static variable is a ‘global’ variable for the function, not the
others.
int f(){
static int s = 0;
return s++;
}
int main() {
cout << f() << endl;
cout << f() << endl;
}
Don’t do it unless you have a good reason!
3
Static Class Members
like a kind of global variables but they have class scope
(outside the class, they cannot be accessed)
 A variable that is part of a class, yet not part of an object of that class,
is called a static member.
 There is exactly one copy of a static member per class, instead of one
copy per object, as for non-static 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
 A function that needs to access to members of a class, yet does not
need to be invoked for a particular object, is called a static member
function.
4
Static Class Members
 Can be declared public, private or protected
 Primitive (Fundamental-type) static data members
 Initialized by default to 0
 If you want a different initial value, a static data member can be initialized
once (and only once)
 A const static data member of int or enum type can be initialized in
its declaration in the class definition
 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
5
Static Class Members
 To access a public static class member when no objects of the class
exist:
 Prefix the class name and the binary scope resolution operator (::) to the
name of the data member
Employee::count
 Also accessible through any object of that class
 Use the object’s name, the dot operator and the name of the member
Employee_object.count
 static member function
 Is a service of the class, not of the object of the class
 Example: SEmployee.h, SEmployee.cpp, static.cpp
Private ‘static’ members still can only be accessed by
member functions!
6
Static Member functions
 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
7
SEmployee.h
 Employee has a static function and a static data member
class Employee
{
public:
Employee(const char *const, const char *const);
~Employee();
const char* getFirstName() const;
const char* getLastName() const;
static int getCount();
private:
char* firstName;
char* lastName;
static int count;
// number of objects instantiated
};
Static data member keeps track of number of Employee objects that currently exist;
Static member function may be called even the object does not exist.
8
SEmployee.cpp (1/3)
// define and initialize static data member at file scope
int Employee::count = 0; // cannot include keyword static
int Employee::getCount()
{
return count;
}
Even static count is private!
 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
9
SEmployee.cpp (2/3)
Employee::Employee(const char *const first, const char *const last)
{
firstName = new char[ strlen( first ) + 1 ];
strcpy(firstName, first);
lastName = new char[ strlen( last ) + 1 ];
strcpy( lastName, last );
count++;
cout << "Employee constructor for " << firstName
<< ' ' << lastName << " called." << endl;
}
 Non-static member function (e.g., constructor) can modify
the class’s static data members
10
SEmployee.cpp (3/3)
Employee::~Employee()
{
cout << "~Employee() called for " << firstName
<< ' ' << lastName << endl;
delete[] firstName;
delete[] lastName;
count--;
}
 Remember to deallocate memory reserved for arrays
11
static.cpp (1/2)
cout << "Number of employees before instantiation of any
objects is " << Employee::getCount() << endl;
Employee* e1Ptr = new Employee( "Susan", "Baker" );
Employee* e2Ptr = new Employee( "Robert", "Jones" );
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()
12
static.cpp (2/2)
cout << "\n\nEmployee 1: " << e1Ptr->getFirstName() << " "
<< e1Ptr->getLastName() << "\nEmployee 2: " <<
e2Ptr->getFirstName() << " " << e2Ptr->getLastName() << "\n\n";
delete e1Ptr;
e1Ptr = 0; // e1Ptr = NULL;
delete e2Ptr;
e2Ptr = 0;
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()
13
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
14
Constant Static Variable
#include <iostream>
using namespace std;
class F {
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 F::count = 2;
int F::getcount() {
cout << count;
}
int main() {
F::getcount(); // print out 2
F::getcount(); // print out 2
cout << F::count; // wrong as 'const int F::count' is private
return 0;
}
15
Constructors with Member
Initializers
How to initialize a ‘const’ private
member?
class Increment {
public:
Increment(int c=0, int i=1);
void addIncrement(){
count += increment;
}
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
17
Increment::Increment(int c, int i)
: count(c),
// initializer for non-const member
increment(i)
// required initializer for const member
{
// empty body
}





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
18
Constructors
with Member Initializer
X::X(parameter_list)
: member_initializer_list
{
// body of constructor definition
}
 Required for initializing
 ‘reference’ data members
 ‘const’ data members
 Member initializer list
 Appears between a constructor’s parameter list and the left brace that begins the
constructor’s body
 Separated from the parameter list with a colon (:)
 Each member initializer consists of the data member name followed by
parentheses containing the member’s construction and its initial value
 Multiple member initializers are separated by commas
 Executes before the body of the constructor executes
19
Examples of member initialization
OK
class F {
public:
F() : 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;
4433
int m; // ANSI C++ cannot have int m = 3;
};
OK
class F {
public:
F() : 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;
};
class F {
NOT OK
public:
F() : i(j), k(m) {
m=3;
j = 4; // compiler complains: assignment of read-only member `F::j'
cout << i << j << k << m << endl;
}
private:
const int& i;
const int j;
int& k;
int m;
};
20
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;
unsigned myMilTime;
};
// 'A' or 'P'
// military time equivalent
21
Default Constructor
Time::Time() : myHours(12), myMinutes(0), myAMorPM('A'), myMilTime(0)
{
// void
}
Time mealTime = Time();
mealTime
myHours
12
myMinutes
0
myAMorPM
A
myMilTime
0
22
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
P
myMilTime
2330 (a random value if myMilTime is not set in set())
23
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
24
 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');
t2
t1
t3
t4
myHours
12
myHours
5
myHours
6
myHours
8
myMinutes
0
myMinutes
0
myMinutes
30
myMinutes
15
myAMorPM
A
myAMorPM
A
myAMorPM
A
myAMorPM
P
myMilTime
0
myMilTime
500
myMilTime
630
myMilTime
2015
25
Copy Operations
 During initialization
Time t = bedTime;
t
bedTime
myHours
11
myHours
11
myMinutes
30
myMinutes
30
myAMorPM
P
myAMorPM
P
myMilTime
2330
myMilTime
2330
Same as: Time t(bedTime); and calls ‘copy constructor’.
 During assignment
t = midnight;
t
midnight
myHours
12
myHours
12
myMinutes
0
myMinutes
0
myAMorPM
A
myAMorPM
A
myMilTime
0
myMilTime
0
‘assignment’, by default, memberwise copy of the left into the right object.
26
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;
}
27
 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";
}
28
Display and Operator Overloading:
do it later …
29
Explicit constructors (not
explicit-value constructor 
Initialization
 T t = v; // assignment syntax
 Where v is of type V, the t is initilized by calling the constructor
T::T(V v).
 T t(v); // explicit syntax
 If v is not of type T, convert v to a temporary T object temp_t;
 Initialize t using the copy constructor T::T(const T&) with temp_t as
argument.
 In most cases, the compiler may optimize such that the
effect of the two is the same. This is the case, e.g. if there
exisit a (non-explicity) constructor T::T(V), where v has
type V.
31
Avoid implicit type conversion
class IntCell
{
public:
explicit IntCell(int initialValue = 0)
: storedValue(initialValue) {}
}
int read( ) const
{return storedValue;}
void write(int x)
{storedValue = x;}
private:
int storedValue;
An explicit constructor will be invoked only explicitly.
 Where a copy constructor is needed, an explicit constructor
will not be implicitly invoked.

32
main(){
int x =
IntCell
IntCell
IntCell
4;
z(5);
t;
u = IntCell(x);
IntCell y = x;
//
//
//
//
//
//
same as int x(4);
now 5 (call explicit-value constructor)
now 0 (call default constructor)
now 4 (call explicit-value constructor,
then copy constructor)
invalid implicit conversion: y = IntCell(x)
…
}
Try to implicitly call IntCell (x), which is ‘explicit’!
If no ‘explicit’ keywork, IntCell y = x; is OK.
33
Objects as class members
Objects as Members of Classes
 A class can have objects of other classes as members
 Sometimes referred to as a ‘has-a’ relationship
 Example: Date.h, Date.cpp, Employee.h, Employee.cpp
and
composition.cpp
class Employee
{
public:
Employee(const
const
const
const
~Employee();
char *const,
char *const,
Date&,
Date&);
void print() const;
private:
char firstName[25];
char lastName[25];
const Date birthDate;
const Date hireDate;
};
const char *const: see ‘pointer’ slides.
35
Employee’s constructor
 Initializing member objects



Member initializers pass arguments from the object’s constructor to member-object
constructors
Before the enclosing class object (host object) is constructed
If a member initializer is not provided, the member object’s default constructor will be called
implicitly
Employee::Employee(const char *const first,
const char *const last,
const Date& dateOfBirth,
const Date& dateOfHire)
: birthDate(dateOfBirth),
hireDate(dateOfHire)
{
...
}


Member initializers pass arguments to Date’s 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
36
Object reference and selfreference: the this pointer
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->getMilTime()
timePtr
or
(*timePtr).getMilTime()
 Call delete to free the memory
t
myHours
12
myMinute
s
0
myAMorP
M
A
myMilTim
e
0
delete timePtr; // call destructor
38
A Member Function Returning a
Reference
 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& f();


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.f() = 10; or i = ncfoo.f();
 const int& f();



This is for non-constant objects. It has to be a rvalue.
i = ncfoo.f(); // good
ncfoo.f() = 10; // wrong: compilation error
 const int& f() const;



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.f(); // good; or i= ncfoo.f();
cfoo.f() = 10; //wrong; and nor ncfoo.f() = 10;
 int& f() const;

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.
 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.
39
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
40
Using the this Pointer when you
want to return the modified object:
F& F::f(){
// …
return *this;
}
 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
41
Summary: static and non-static
members
class A {
…
int l;
static int g;
}
A a,b,c,d, … ;
A::g
a.g = b.g = c.g = d.g =
… = A::g (one copy)
a.l
b.l
c.l
d.l (multiple copies)
Members of the class, not that of the objects
member data, non-static, so far belong to ‘objects’ or
‘instances’ of the class
 member data, static, are ‘variables’ of the class, not the
objects.

General form of ‘constructors’
X::X(…)
: …
{
…
}
 Have to use ‘member initializers’ for
 ‘reference’ data members
 ‘const’ data members
class A {
…
int& r;
const int c;
}
43
Separate compilation
Interface and Implementation
 In C++ it is more common to separate the class interface
from its implementation.
 Abstract data type
What to do?
 The interface lists the class and its members (data and
functions).
 The implementation provides implementations of the
functions.
How to do?
45
Interface
 Describes what services a class’s 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 class’s interface consists of the class’s public member functions
(services)
46
Separate File for Reusability
 .cpp source-code files
 .h header files
 Separate files in which class definitions are placed
 Allow compiler to recognize the classes when used elsewhere
 Generally have .h filename extensions
 Driver files
 Program used to test software (such as classes)
 Contains a main function so it can be executed
 See GradeBook4.h and Gradebook4.cpp
47
#include preprocessor directive
#include "GradeBook.h"
 include header files
 Instructs C++ preprocessor to replace directive with a copy of the
contents of the specified file
 Quotes for user-defined header files
 Preprocessor first looks in current directory
 If the file is not found, looks in C++ Standard Library directory
 Angle brackets for C++ Standard Library
 Preprocessor looks only in C++ Standard Library directory
 #include <iostream>
48
IntCell::IntCell(int initialValue)
: storedValue(initialValue)
class IntCell {
{ }
public:
explicit IntCell(int initialValue = 0 );
int read( ) const;
int IntCell::read( ) const
{return storedValue;}
void write( int x );
void IntCell::write(int x)
private:
int storedValue;
{storedValue = x;}
}
IntCell.h
IntCell.cpp
The interface is typically placed in a file that ends with .h.
The implementation file typically ends with .cpp, .cc, or .C.
49
Separate Class 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
 Use binary scope resolution operator (::) to “tie” each member function
to the class definition
 Implementation details are hidden
 Client code does not need to know the implementation
 In the header file for a class
 Function prototypes describe the class’s public interface
50
Class Libraries
 Class declarations placed in header file
 Given .h extension
 Contains data items and prototypes
 Implementation file
 Same prefix name as header file
 Given .cpp extension
 Programs which use this class library called client
programs
51
Reality: the separation is not
perfect
 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
52
Typical C++ Development
Environment
 Edit
 Programmer writes program (and
stores source code on disk)
 Preprocess
 Perform certain manipulations and file
I/O before compilation
 Compile
 Compiler translates C++ programs into
machine languages in object codes
 Link
 Link object codes with missing
functions and data
 Load
 Transfer executable image to memory
 Execute
 Execute the program one instruction at
a time
53
The Compilation and Linking Process
 Source-code file is compiled to
create the class’s 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
54
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
e.g.,
g++ foo.cpp bar.o fb.o
Library
Object File
55
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
56
Why #ifndefine #define #endif
Statement?
 It is ok to have multiple declarations of a function prototype,
but not for its definition
 In the .h file, put the prototypes there
 .h files are likely to be multiply-included
 In creating the .o file, there may be nested #include statement
 The nested #include statement may be recursive
 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.
57
Data Integrity
 Data integrity are not automatic by putting data members
as private
 The programmer must provide appropriate validity checking and
report the errors
 Member functions that set the values of private data
should verify that the intended new values are proper
 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
58
Gradebook6.h (with Validity
Checking)
#ifndef GRADEBOOK_H
#define GRADEBOOK_H
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
59
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
60
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
61
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
62
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
63
Download