Title: Advanced Issues on Classes
1Advanced Issues on Classes
- Part 1 (2hrs)
- -sharing a variable among several objects of the
same class (reference variables, pointers) - iterators
- Part 2 (3hrs)
- constructor, destructor, copy constructor, deep
copy, assignment operator - operator overloading
- Horton pp.334... (a bit better, more compact)
- Appendix E in Tapestry
2(destructor, constructor reminder)copy
constructor, deep copy
3Destructor reminder Tapestry pp. 625
- Each class should also have a destructor which
should take care of returning any unreturned
memory. - The destructor has name classname similar to
that of the constructor - e.g. linkedlist()
- The destructor is called automatically when
- the object goes out of scope or
- the programmer deletes the object
4DestructorTapestry pp. 624
- int CountUnique (ifstream input)
-
- string word
- LinkStringSet set //similar to
linkedlistltstringgt - while (input gtgt word) //by inserting words into
a set which - set.insert(word) //skips the insertion if the
element is already in the set - //we can count how many elements (words) are
unique - return set.size
-
- What happens to set when this function returns?
5DestructorTapestry pp. 624
- When a class instance goes out of scope, the
class destructor is automatically called - e.g. for the LinkStringSet object in the prev.
slide - Since the compiler makes this call automatically,
it creates a a dummy destructor for each class
that does not contain a destructor. So, - if the programmer has not supplied a destructor,
the one which is created by the compiler is
called - This basically prevents the program from
crashing, but as a dummy function, it is not
guaranteed to do the right thing (e.g. doesnt
free all memory) - if the programmer has supplied one, compiler
wont generate a dummy destructor - Remember that the (real) destructor should free
all memory taken with new - LinkStringSetLinkStringSet()
-
- reclaimnodes(myhead)
- myhead 0
6Copy Constructor
- Special constructor called when an object is
first defined and initialized from another object
of the same type - Example
- LinkedList list3(list)
- Date today
- Date tomorrow (today1)
- Date yesterday (today-1)
- //Date yesterday tomorrow //this is not a
copy constructor -
- Syntax
- linkedlistlinkedlist (const linkedlist l)
- datedate (const date d)
7Copy Constructor Example
- LinkedList list1
- list1.InsertOrdered(7)
- list1.PrintList()
- list1.InsertOrdered(4)
- list1.PrintList()
-
- LinkedList list2(list1)
- list2.PrintList()
- list1.DeleteList()
- list2.PrintList() //We want to be able to do
this!
8Copy Constructor
-
- For every class, there is a default copy
constructor (compiler provided) - Simply copies the value of each instance variable
from one object to the other. - Default copy constructor can only do a shallow
copy only the private data of a class instance
is copied. - In the case of a linked list, this would be the
head pointer, NOT the whole list - The new list share the same memory as the old
one! - what can we do if we want what is called a deep
copy (make a copy of the nodes etc. too) - e.g. LinkedList list2(list1)
9Shallow Copy
-
- If you say
- list2 list1
- This is what happens
-
list1 3 4
5
list2
10Deep Copy
-
- If you want to be able to assign objects like
lists, you want to copy the whole list to another
object - hence the name deep copy
- you must provide a proper copy constructer for
your class (using the compilers dummy version is
not enough) - LinkedList list2(list1)
list1 3 4
5
list2 3 4
5
11Deep Copy How?
- e.g. LinkedStringSet list2(list1)
-
- LinkStringSetLinkStringSet (const
LinkStringSet set) - myFirst(new Node("header",set.clone())),
//same as myFirst new Node("header",set.clone()
)) - mySize(set.size()) //see the color
illustration below -
- // deep copy made in an initializer list
-
- The newly created object is calling a helper
function called clone() - Shown in the next slides
- Remember private variables and functions can be
accessed by objects of the same class (or by
friend classes) -
list2.myFirst 3 4
5 list1.myFirst
header
3 4 5
.
12- LinkStringSetNode LinkStringSetclone()
const -
- Node front("front",0)
- Node last front
-
- Node temp myFirst-gtnext
- while (temp ! 0)
- last-gtnext new Node(temp-gtinfo,0)
- last last-gtnext
- temp temp-gtnext
-
- return front.next
-
13Operator Overloading
14Assignment Operator
- Lets overload (make it work for your own class)
the assignment operator. - Syntax const foo foooperator (const foo
f) - e.g. const linkedlist linkedlistoperato
r (const linkedlist l) - Usage list2 list1
- Compiler interprets this as list2.operator(list1
) - Similar to the copy constructor, but the
assignment operator is called to reinitialize an
object that has already been constructed. - Since the object already exists, more bookkeeping
is necessary
15- LinkedList list, l3
- ...
- list.InsertOrdered(7)
- list.PrintList()
- list.InsertOrdered(4)
- list.PrintList()
- ...
- LinkedList list2(list) //copy constructor
list2(list) - list2.PrintList()
- list3 list //assignment op.
l3.operator(list) - list3.PrintList()
- list.DeleteList()
- list2.PrintList()
- list3.PrintList()
16Assignment Operator
- const foo
- foooperator (const foo f)
- const LinkStringSet
- LinkStringSetoperator (const LinkStringSet
set) -
- if (set ! this) //this is a pointer each
object has to itself - reclaimNodes(myFirst-gtnext) //this is b
- myFirst-gtnext set.clone() //copy a
- mySize set.size()
-
- return this //return b
-
- ...
- //Usage of the assgnmnt. operator
- b a //b will represent a different object
than before
17Assignment Operator explanation
- const LinkStringSet
- LinkStringSetoperator (const LinkStringSet
set) -
- if (set ! this) //to prevent misbehaviour
if aa is used - reclaimNodes(myFirst-gtnext) //free
memory of rhs - myFirst-gtnext set.clone() //copy lhs
- mySize set.size()
-
- return this //return rhs for situations
when - //a b c is used
- //which is equal to the statement
- //a (b c)
- b a
18- LinkStringSetLinkStringSet (const
LinkStringSet set) - myFirst(new Node("header",set.clone())),
- mySize(set.size())
- // uses header node
- // initializer list made deep copy
-
- const LinkStringSet
- LinkStringSetoperator (const LinkStringSet
set) -
- if (set ! this)
- reclaimNodes(myFirst-gtnext)
- myFirst-gtnext set.clone()
- mySize set.size()
-
- return this
-
- LinkStringSetNode LinkStringSetclone()
const
Linkstringset.cpp
19Linksetdemo.cpp
- int main()
-
- LinkStringSet a,b
-
- a.insert("apple")
- a.insert("cherry")
- cout ltlt "a " Print(a) //cherry apple 2
- b a
- cout ltlt "b " Print(b) //cherry apple 2
- a.clear()
- cout ltlt "a " Print(a) // 0
- cout ltlt "b " Print(b) //cherry apple 2 -
- //as intended with , provided by deepcopy in
linkstringset.cpp - return 0
-
- Complete project is in linkstringset.zip you
should play with it.
20Tapestry Chp. 9.4clockt.h and clockt.cpp
- We will now look at the Tapestrys clock class
for - more operator overloading
- class design
- How to design a clocktime class?
- to represent a clock-time object 195900
21ClockTime Class
- class ClockTime
-
- public
- ClockTime()
- ClockTime(int secs, int mins, int hours)
-
- int Hours() const //
returns hours - int Minutes() const //
returns minutes - int Seconds() const //
returns seconds - string tostring() const //
converts to string -
- bool Equals(const ClockTime ct) const
// true if ct - bool Less (const ClockTime ct) const
// true if lt ct - const ClockTime operator (const
ClockTime ct) -
- private
- void Normalize() //normalized form
should be like 0-24hr0-60min0-60sec - int mySeconds // constrained 0-59
- int myMinutes // constrained
0-59
22- ClockTimeClockTime (int secs, int mins, int
hours) - mySeconds(secs), myMinutes(mins),
myHours(hours) - // postcondition all data fields initialized
-
- Normalize()
-
- void ClockTimeNormalize()
-
- myMinutes ...
- mySeconds ...
-
- myHours ...
- myMinutes ...
23- ClockTimeClockTime (int secs, int mins, int
hours) - mySeconds(secs), myMinutes(mins),
myHours(hours) - // postcondition all data fields initialized
-
- Normalize()
-
- void ClockTimeNormalize()
-
- myMinutes mySeconds/60 // overflow
from secs to myMinutes - mySeconds 60 // now
between 0 and 59 -
- myHours myMinutes/60 // overflow
from myMinutes to myHours - myMinutes 60 // now
between 0 and 59
24Helper Functions of the clocktime class
- These will be used in operator overloading. They
implement the straightforward meaning (make sure
you understand) - bool ClockTimeEquals (const ClockTime c)
const //usage c1.Equals(c2) - // postcondition returns true iff this objects
time c -
- return ( Hours() c.Hours()
- Minutes() c.Minutes()
- Seconds() c.Seconds() )
-
- Alternative
- bool ClockTimeEquals (const ClockTime c)
const - // postcondition returns true iff this objects
time c -
- return ( myHours c.myHours
- myMinutes c.myMinutes
- mySeconds c.mySeconds )
-
25Helper Functions of the clocktime class
- These will be used in operator overloading. They
implement the straightforward meaning (make sure
you understand) - bool ClockTimeLess (const ClockTime c) const
//usage c1.Less(c2) - // postcondition returns true iff lt c
-
- return ( Hours() lt c.Hours() )
- ( ( Hours() c.Hours() )
- ( ( Minutes() lt
c.Minutes() ) - ( ( Minutes()
c.Minutes() ) ( Seconds() lt c.Seconds() ) ) - )
- )
26Overloading Operators
- Now lets overload the operator gt. First notice
that we should be able to use the gt operator
with clocktimes in 3 ways - clocktime c1, c2
- int n 1
- if ( c1 gt c2) or
- if ( c1 gt 1) (let this mean c1 is more than
or equal to 1 hr) - or
- if ( 1 gt c1) ...
-
27Overloading complete case for gt
- Now lets overload the operator gt.
- First notice that we should be able to use the gt
operator with clocktimes in 3 ways - clocktime c1, c2
- int n 1
- if ( c1 gt c2) //calls c1.operatorgt(c2) b
ool Clocktimeoperatorgt(const clocktime rhs) - return ! ( Less(rhs) ) //uses the helper
function Less() of c1. -
- if ( c1 gt 1) //calls c1.operatorgt(1) let
this mean is the time more than 1 hr - bool Clocktimeoperatorgt(const int rhs)
- return ( Hours() gt rhs )
- //uses the accessor function Hours() of c1.
- //alternative return ( myHours gt rhs )
- //since the member functions can access
private data -
- if ( 1 gt c1) //cannot call
1.operatorgt(c1) since 1 is a constant, so this
version of the operatorgt must be a free
function -
28Overloading complete case for gt
- if ( c1 gt c2) //calls c1.operatorgt(c2) b
ool Clocktimeoperatorgt(const clocktime rhs) - return ! ( Less(rhs) ) //uses the helper
function Less() of c1. -
- if ( c1 gt 1) //calls c1.operatorgt(1) let
this mean is the time more than 1 hr - bool Clocktimeoperatorgt(const int rhs)
- return ( Hours() gt rhs )
- //uses the accessor function Hours() of c1.
- //alternative return ( myHours gt rhs )
- //since the member functions can access
private data -
- if ( 1 gt c1) //cannot call
1.operatorgt(c1) since 1 is a constant, so this
version of the operatorgt must be a free
function - bool operatorgt(const int lhs, const
clocktime rhs) - return ( lhs gt rhs.Hours() )
-
-
29Overloading complete case for gt
- This function appears as a free function (outside
class definition) - bool operatorgt(const int lhs, const clocktime
rhs) -
- return ( lhs gt rhs.Hours() )
-
- If the clocktime class did not provide an
accessor function Hours(), we would have a
problem, since free functions cannot access
private data (myHours) - Alternatively, we could make the free function a
friend function of the clocktime class - Add friend bool operatorgt(const int lhs,
const clocktime rhs) in the class declaration
(before the keyword public).
30Operator
- Usage Interpreted as
- c1 ct c1.operator(ct)
- const ClockTime ClockTimeoperator (const
ClockTime ct) - // postcondition add ct, return result
(normalized for myMinutes, mySeconds) -
- mySeconds ct.mySeconds
- myMinutes ct.myMinutes
- myHours ct.myHours
- Normalize()
- return this
-
-
31- why operator returns this?
- same arguments as for the assignment operator ()
- in case someone uses clockt c1 (c2 c3)
etc. - This is ugly (do not use statements like this),
but in general one should design the same
behavior as it exists for built-in types (it is
legal to say this for ints etc)
32Clocktime.cpp other overloaded operators
- In clocktime cpp, only some forms of the
overloaded operators are provided (apparently
they did not see a good use comparing clocktime
objects to constants etc.) and most are declared
as free functions - ostream operator ltlt (ostream os, const
ClockTime ct) - ClockTime operator (const ClockTime lhs,
const ClockTime rhs) - bool operator (const ClockTime lhs, const
ClockTime rhs) - bool operator ! (const ClockTime lhs, const
ClockTime rhs) - bool operator lt (const ClockTime lhs, const
ClockTime rhs) - bool operator gt (const ClockTime lhs, const
ClockTime rhs) - bool operator lt (const ClockTime lhs, const
ClockTime rhs) - bool operator gt (const ClockTime lhs, const
ClockTime rhs) - However, most of these particular functions
can/should be member functions - (except for the ltlt operator which has to be a
free function) - since they have a left-hand-side which is a
clocktime object, they can be member functions
(which is better) - But as shown in the previous slide, when we are
writing versions of the overloaded operators
which has constants on the left-hand-side, they
have to be free functions using accessors, or be
free friend functions, as shown before.
33Operator
- Usage Interpreted as
- c c1 c2 c (operator(c1,c2))
- The free function operator using the previously
defined operator of the class - ClockTime operator (const ClockTime lhs, const
ClockTime rhs) - // postcondition return lhs rhs (normalized
for myMinutes, mySeconds) -
- .............................. //uses the
previously defined copy constructor - .............................. //uses the
previously defined operator - .............................
-
-
34- The free function operator using the previously
defined operator of the class - ClockTime operator (const ClockTime lhs, const
ClockTime rhs) - // postcondition return lhs rhs (normalized
for myMinutes, mySeconds) -
- ClockTime result(lhs) //uses the previously
defined copy constructor - result rhs //uses the previously
defined operator - return result
-
- why operator makes a copy first?
- c a b should not change as value
35Overloading I/O operators
- ostream operator ltlt (ostream os, const
ClockTime ct) - // postcondition inserts ct onto os, returns os
- // format is hms
-
- os ltlt ct.tostring()
- return os
-
- string ClockTimetostring() const
-
- ostringstream os //to use a string as a
stream - os.fill('0') //fill it with 0s
- os ltlt Hours() ltlt "" ltlt setw(2) ltlt Minutes()
ltlt "" - ltlt setw(2) ltlt Seconds() 10959
-
- return os.str()
-
36Overloading I/O operators
- ostream operator ltlt (ostream os, const
ClockTime ct) - // postcondition inserts ct onto os, returns
os - // format is hms
-
- os ltlt ct.tostring()
- return os
-
- operator ltlt cannot be a member function (in
general) - cout ltlt c1 // ltlt is also a member function of
cout //which would cause a source of
conflict/confusion - ostream (output streams) has to be passed as
reference - Since the ostream is modified when you put
something on the string - operator ltlt must return the os
- in case we use cout ltlt c1 ltlt c2 since cout is
left associative, the result of - cout ltlt c1 must be the os.
37Overloading I/O operators
This is an alternative not using the tostring()
but using accessor functions directly instead
(it has to, because free functions cannot access
private data of a class). But the tostring()
version is better.
- ostream operator ltlt (ostream os, const
ClockTime ct) - // postcondition inserts ct onto os, returns os
-
- ostringstream ostr
- ostr.fill('0')
- ostr ltlt ct.Hours() ltlt "" ltlt setw(2) ltlt
ct.Minutes() ltlt "" - ltlt setw(2) ltlt ct.Seconds()
- os ltlt ostr.str()
- return os
-
string ClockTimetostring() const
ostringstream os //to use a string as a stream
os.fill('0') //fill it with 0s os ltlt
Hours() ltlt "" ltlt setw(2) ltlt Minutes() ltlt ""
ltlt setw(2) ltlt Seconds() return
os.str()
38Other overloaded operators
- bool operator (const ClockTime lhs, const
ClockTime rhs) -
- return lhs.Equals(rhs)
-
- bool operator ! (const ClockTime lhs, const
ClockTime rhs) -
- return ! (lhs rhs)
-
- ...
39Linkstringsetiterator.h
- class LinkListIterator
-
- public
- LinkListIterator(const LinkList
list) //constructor - myList(list), myCurrent(0)
-
- void Init() //initialize the iterator
- myCurrent myList.myFirst-gtnext
-
- bool HasMore() const //more nodes on the
list? - return myCurrent ! 0
-
- string Current() const //return the info
of the current node - return myCurrent-gtinfo
-