Ch 14: More About Classes 14.1 Instance and Static Members

! : a member variable in a class. Each object (instance) has its own copy.

CS 2308 ! : one variable shared among all Fall 2013 objects of a class

Jill Seaman ! static member function: - can be used to access static member variable; ‣ normal functions can access static member variables, too - but it cannot access instance variables 1 - can be called before any objects are defined2

string name1 = “Steve Jobs”; string name1 = “Steve Jobs”; cout << “Name” << name1 << endl; cout << “Name” << name1 << endl;

Tree class declaration Program demo of static variable

// Tree class class Tree { private: Static member variable #include static int objectCount; declared here using namespace std; public: #include "Tree.h" Tree(); int getObjectCount(); int main() { }; Tree oak; Tree elm; // Definition of the static member variable, written Tree pine; // outside the class. Static member variable int Tree::objectCount = 0; defined here (required) cout << “We have “ << pine.getObjectCount() // Member functions defined << “Trees in our program.\n”; Tree::Tree() { Static variable is incremented objectCount++; each time Tree is constructed. } } int Tree::getObjectCount() { return objectCount; What will be the output? } 3 4 string name1 = “Steve Jobs”; string name1 = “Steve Jobs”; cout << “Name” << name1 << endl; cout << “Name” << name1 << endl; Three Instances of the Tree Class, static member function But Only One objectCount Variable

! Declared with static before return type: Put in the class static int getObjectCount(); declaration

! Static member functions can access static member data only

int Tree::getObjectCount() { Don’t need static return objectCount; keyword here. }

! Can be called independently of objects (use class name):

5 cout << “We have “ << Tree::getObjectCount() 6 << “Trees in our program.\n”;

static int getObjectCount(); string name1 = “Steve Jobs”; cout << “Name” << name1 << endl;

14.3 Member-wise Assignment Member-wise assignment: demo

! Can use = to Time t1(10, 20); - assign (copy) one object to another, or Time t2(12, 40); cout << “t1: “ << t1.display() << endl; - initialize an object with another object’s data cout << “t2: “ << t2.display() << endl; ! Copies member to member. e.g., Just like = for structs t2 = t1; instance2 = instance1; cout << “t1: “ << t1.display() << endl; cout << “t2: “ << t2.display() << endl; means: copy all member values from instance1 and assign to the corresponding member Output: variables of instance2 t2 = t1; //equivalent to: t1: 10:20 t2.hour = t1.hour; t2: 12:40 ! Time t2 = t1; t2.minute = t1.minute; t1: 10:20 Also used at initialization: t2: 10:20 7 8 string name1 = “Steve Jobs”; string name1 = “Steve Jobs”; cout << “Name” << name1 << endl; cout << “Name” << name1 << endl;

14.4 Copy Constructors IntCell declaration

! Special constructor used when a newly created ! Problem: what if the object contains a pointer? object is initialized using another object of the same class. class IntCell { private: Time t1; int *storedValue; //ptr to int Time t2 (t1); Both of the last two Time t3 = t1; use the copy constructor public: IntCell (int initialValue); ~IntCell(); - [used implicitly when passing arguments by value] int read () const; void write (int x); ! The default copy constructor copies -to-field }; (member-wise assignment). ! Default copy constructor works fine in many cases 9 10

string name1 = “Steve Jobs”; string name1 = “Steve Jobs”; cout << “Name” << name1 << endl; cout << “Name” << name1 << endl; Problem with member-wise IntCell Implementation assignment

#include “IntCell.h” ! What we get from member-wise assignment in IntCell::IntCell (int initialValue) { objects containing dynamic memory (ptrs): storedValue = new int; *storedValue = initialValue; IntCell object1(5); } IntCell object2 = object1; // calls copy constructor IntCell::~IntCell() { delete storedValue; //object2.storedValue=object1.storedValue } object2.write(13); int IntCell::read () const { cout << object1.read() << endl; return *storedValue; cout << object2.read() << endl; }

void IntCell::write (int x) { What is output? 5 13 *storedValue = x; 13 or 13 }

11 12 string name1 = “Steve Jobs”; string name1 = “Steve Jobs”; cout << “Name” << name1 << endl; cout << “Name” << name1 << endl; Problem with member-wise Programmer-Defined assignment Copy Constructor

! Why are they both changed to 13? ! Prototype and definition of copy constructor:

! Member-wise assignment does a shallow copy. IntCell(const IntCell &obj); Add to class declaration It copies the pointer’s address instead of allocating new memory and copying IntCell::IntCell(const IntCell &obj) { storedValue = new int; ! As a result, both objects point to the same *storedValue = obj.read(); //or *(obj.storedValue) location in memory }

! 13 Copy constructor takes a reference parameter to object1 object2 an object of the class storedValue storedValue - otherwise, pass-by-value would use the copy constructor to initialize the obj parameter, which 13 would call the copy constructor: this is an infinite14 loop

static int getObjectCount(); string name1 = “Steve Jobs”; string name1 = “Steve Jobs”; cout << “Name” << name1 << endl; cout << “Name” << name1 << endl; Programmer-Defined Copy Constructor: limitations Copy Constructor ! Copy constructor is called ONLY during ! Each object now points to separate dynamic memory: initialization of an object, NOT during assignment. IntCell object1(5); IntCell object2 = object1; //now calls MY copy constr ! If you use assignment with IntCell, you will still object2.write(13); end up with member-wise assignment and a cout << object1.read() << endl; Output: 5 cout << object2.read() << endl; 13 shared value:

5 13 IntCell object1(5); object1 object2 IntCell object2(0); object2 = object1; //object2.value=object1.value

storedValue storedValue object2.write(13); cout << object1.read() << endl; Output: 13 cout << object2.read() << endl; 13 15 16 string name1 = “Steve Jobs”; string name1 = “Steve Jobs”; cout << “Name” << name1 << endl; cout << “Name” << name1 << endl;

14.5 Operator Overloading Operator Overloading

! Operators such as =, +, <, and others can be ! Prototype in Time class declaration: defined to work for objects of a user-defined class int operator- (Time right); t1 - t2 will return the ! total number of minutes The name of the function defining the over-loaded between t1 and t2 operator is operator followed by the operator ! operator- is the function name symbol: ! The operator function is defined from the operator+ to define the + operator, and perspective of the object on the left side of the - operator= to define the = operator - hour and minute will be from the left hand side (t1)

! Just like a regular member function: ! Time right is the parameter for the right hand - Prototype goes in the class declaration side of operator (t2). - Function definition goes in implementation file ! The operator function is called via object on left 17 side 18

static int getObjectCount(); string name1 = “Steve Jobs”; string name1 = “Steve Jobs”; cout << “Name” << name1 << endl; cout << “Name” << name1 << endl;

Invoking an Overloaded Operator Example: minus for Time objects

! Operator can be invoked (called) like a normal class Time { Subtraction member function: ! private: ! int hour, minute; int minutes = object1.operator-(object2); ! public: ! int operator- (Time right); }; ! It can also be called using the more conventional operator syntax: int Time::operator- (Time right) { //Note: 12%12 = 0 return (hour%12)*60 + minute - int minutes = object1 - object2; ((right.hour%12)*60 + right.minute); } This is the main reason to overload operators, so you can use this syntax for objects of your class //in a driver: Time time1(12,20), time2(4,40); ! Both call the same operator- function, from the int minutesDiff = time2 - time1; perspective of object1 cout << minutesDiff << endl; Output: 260 19 20

static int getObjectCount(); string name1 = “Steve Jobs”; string name1 = “Steve Jobs”; cout << “Name” << name1 << endl; cout << “Name” << name1 << endl;

Overloading == and < for Time Overloading == and < for Time

class Time { bool Time::operator== (Time right) { private: if (hour == right.hour && int hour; minute == right.minute) int minute; return true; void addHour(); else public: return false; Time(); } Time(int); Time(int,int); void addMinute(); //adds one minute bool Time::operator< (Time right) { void addMinute(int); //adds n minutes if (hour == right.hour) int getHour(); return (minute < right.minute); int getMinute(); return (hour%12) < (right.hour%12); int operator- (Time right); } bool operator== (Time right); bool operator< (Time right); //in a driver: Time time1(12,20), time2(12,21); void setHour(int); void setMinute(int); if (time1

string name1 = “Steve Jobs”; string name1 = “Steve Jobs”; cout << “Name” << name1 << endl; cout << “Name” << name1 << endl;

Overloading + for Time Overload = for IntCell class Time { class IntCell { Now = for IntCell will not private: private: use member-wise assignment int hour, minute; int *value; public: public: Time operator+ (Time right); IntCell(const IntCell &obj); }; IntCell(int); Time Time::operator+ (Time right) { //Note: 12%12 = 0 ~IntCell(); int totalMin = (hour%12)*60 + minute + int read() const; (right.hour%12)*60 + right.minute; void write(int); int h = totalMin / 60; //integer division, total hours void operator= (IntCell rhs); h = h%12; //keep it between 0 and 11 }; if (h==0) h = 12; //convert 0:xx to 12:xx Time result(h, totalMin % 60); //create new time obj void IntCell::operator= (IntCell rhs) { return result; write(rhs.read()); } } //in a driver: Time t1(12,5); //in a driver: Output: 2:55 Time t2(2,50); IntCell object1(5), object2(0); Time t3 = t1+t2; object2 = object1; Output: 5 cout << t3.display() << endl; 23 object2.write(13); 24 cout << object1.read() << endl;