Ch 14: More About Classes 14.1 Instance and Static Members
! instance variable: a member variable in a class. Each object (instance) has its own copy.
CS 2308 ! static variable: 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
! 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 field-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;