Classes Part 2 Static class members Static vs
Classes: Part 2
Static class members
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’ has a ‘reserved’ specific meaning: § ‘static’ variables are ‘global’ with the file scope 3
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; } Don’t do it unless you have a good reason! 4
Static class members § A variable that is part of a class, but not part of an object of that class, is called a static member. like a kind of global variables but they have class scope (outside the class, they cannot be accessed) § There is exactly one copy of a static member per class, instead of one copy per object for non-static members A static variable is shared by all objects of the class! 5
class A { … int l; static int g; } A a, b, c, d, … ; a. l b. l c. l d. l (multiple copies) a. g = b. g = c. g = d. g = … = A: : g (one copy) A: : g Members of the class, not that of the objects member data, non-static, so far belong to ‘objects’ or ‘instances’ of the class l member data, static, are ‘variables’ of the class, not the objects. l
Public static class member § To access a public static class member when no objects of the class exist: A: : g Private static class member Private ‘static’ members are still only to be accessed by member functions! § Also accessible through any object of that class a. g 7
Initialization: primitive types By default, a static class member is initialized to zero. class A { Public: static int g; } int A: : g = 1; Initialization, has to go with the file of the class int main() { A: : g = 100; }
Constant static class members class A { Public: const static int c = 100; } a const static class member can be initialized in the class defintion. class A { Public: const static int c; } const int A: : c = 1; Or , has to go with the file of the class
Constant static member class F { public: static int getcount(); private: const static int count = 2; }; int F: : getcount() { cout << count; } int main() { F: : getcount(); // print out 2 } 10
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; } It is only possible for initialization, but not an access! int main() { F: : getcount(); // print out 2 cout << F: : count; // wrong as 'const int F: : count' is private return 0; } 11
A static member of a class type (not a primitive type) is not initialized, but constructed by the default-value constructor 12
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 13
Example (SEmployee. h) class Employee { public: Employee(const char *const, const char *const); ~Employee(); const char* get. First. Name() const; const char* get. Last. Name() const; static int get. Count(); private: char* first. Name; char* last. Name; 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. 14
class Employee { public: Employee(const char *const, const char *const); ~Employee(); const char* get. First. Name() const; const char* get. Last. Name() const; static int get. Count(); private: char* first. Name; char* last. Name; static int count; // number of objects instantiated }; // define and initialize static data member at file scope int Employee: : count = 0; // cannot include keyword static Even static count is private! int Employee: : get. Count() { return count; } § 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 calle 15 when no objects exists
Employee: : Employee(const char *const first, const char *const last) { first. Name = new char[ strlen( first ) + 1 ]; strcpy(first. Name, first); last. Name = new char[ strlen( last ) + 1 ]; strcpy( last. Name, last ); count++; cout << "Employee constructor for " << first. Name << ' ' << last. Name << " called. " << endl; } § Non-static member function (e. g. , constructor) can modify the class’s static data members 16
Employee: : ~Employee() { cout << "~Employee() called for " << first. Name << ' ' << last. Name << endl; delete[] first. Name; delete[] last. Name; count--; } § Remember to deallocate memory reserved for arrays 17
static. cpp (1/2) cout << "Number of employees before instantiation of any objects is " << Employee: : get. Count() << endl; Employee* e 1 Ptr = new Employee( "Susan", "Baker" ); Employee* e 2 Ptr = new Employee( "Robert", "Jones" ); cout << "Number of employees after objects are instantiated is “ << e 1 Ptr->get. Count(); § 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: : get. Count() 18
cout << "nn. Employee 1: " << e 1 Ptr->get. First. Name() << " " << e 1 Ptr->get. Last. Name() << "n. Employee 2: " << e 2 Ptr->get. First. Name() << " " << e 2 Ptr->get. Last. Name() << "nn"; delete e 1 Ptr; e 1 Ptr = 0; // e 1 Ptr = NULL; delete e 2 Ptr; e 2 Ptr = 0; cout << "Number of employees after objects are deleted is " << Employee: : get. Count() << endl; § Even when no object exists, we can still call static member function get. Count() 19
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: : get. Count() = 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 20
Type conversions 21
Assignments of different classes class T { . . . public: . . . T& operator=(const T&); }; T& operator=(const X&); T& operator=(const int); . . . main() { T a, b; X x, y; … b = a; // b. operator=(a) … a = x; // a. operator=(x) a = 10; // a. operator=(10) } 22
Constructors from a different class T { . . . public: . . . T(const X& x); . . . }; main() { X x, y; T c(x), d(y); } 23
If not defined, automatic converstion … class A { public: A (int i); A& operator=(const A&); // A& operator=(int i) }; A a; a = 10; A a; A temporary(10); // or temporary = 10; a = temporary; The compilor will do the convertion 24
More generally, for any classes: class A {}; class B { public: B (A a) {}; B& operator=(const B&); // B& operator=(const A&); }; A a; B b; b = a; // B temp(a); // b. operator=(temp); 25
‘explicit’ constructors (not explicitvalue constructors) A a; a = 10; No, types do not match! A a; A temporary(10); // or temporary = 10; a = temporary; The compile will do if no ‘explicit’! class A { public: explicit A(int i); … } 26
Example: Avoid implicit type conversion class Int. Cell { public: explicit Int. Cell(int initial. Value = 0) : stored. Value(initial. Value) {} } int read( ) const {return stored. Value; } void write(int x) {stored. Value = x; } private: int stored. Value; 27
main(){ int x = 4; // same as int x(4); Int. Cell z(5); // now 5 (call explicit-value constructor) Int. Cell t; // now 0 (call default constructor) Int. Cell u = Int. Cell(x); // now 4 (call explicit constructor) Int. Cell y = x; // invalid implicit conversion: y = Int. Cell(x) } Try to implicitly call Int. Cell (x), which is ‘explicit’! If no ‘explicit’ keywork, Int. Cell y = x; is OK. 28
Recommendations § Make all one-parameter constructors ‘explicit’ to avoid behind-the-scene type conversions. § Keep ‘strong typing’ is desirable, avoid hard-to-find bugs 29
Constructors with initializers
How to initialize a ‘const’ private member? class Increment { public: Increment(int c=0, int i=1); void add. Increment(){ count += increment; } private: int count; const increment; }; § It is not ‘static’, so ‘the const increment’ is different for each object! § It has to be initialized with a new mechanism using a member initializer 31
Increment: : Increment(int c, int i) : count(c), increment(i) { } (See Increment. h, Increment. cpp and const 2. cpp) 32
Constructors with Member Initializer § General form of ‘constructors’ X: : X(parameter-list) : initializer-list { … } § Required for initializing § ‘const’ data members § (‘reference’ data members, NOT OFTEN used!) § Member initializer list § Each member initializer consists of the data member name followed by its initial value in parentheses § is executed before the body of the constructor 33
Examples 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; }; 34
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 char *const, const Date&, const Date&); ~Employee(); void print() const; private: char first. Name[25]; const char *const: see ‘pointer’ slides. char last. Name[25]; const Date birth. Date; const Date hire. Date; 36 };
Constructor § Initializing member objects § § Member initializers pass arguments from the object’s constructor to member-object constructors § 1. initializers § 2. member-object constructors § 3. object constructors 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& date. Of. Birth, const Date& date. Of. Hire) : birth. Date(date. Of. Birth), hire. Date(date. Of. Hire) { . . . } § § Member initializers pass arguments to Date’s implicit copy constructor (equivalent to const Date birth. Date = date. Of. Birth; ) A compilation error occurs if a const member object is not initialized with a member initializer in the constructor 37
Example: Time Class § Information hiding (Time. h and Time. cpp) § Two types of constructors class Time { public: Time(); Time(unsigned init. Hours, unsigned init. Minutes, char init. AMPM); void set(unsigned hours, unsigned minutes, char am_pm); void display(ostream& out) const; . . . private: unsigned my. Hours, my. Minutes; char my. AMor. PM; // 'A' or 'P' unsigned my. Mil. Time; // military time equivalent }; 38
Default Constructor Time: : Time() : my. Hours(12), my. Minutes(0), my. AMor. PM('A'), my. Mil. Time(0) { // void } Time meal. Time = Time(); meal. Time my. Hours 12 my. Minutes 0 my. AMor. PM A my. Mil. Time 0 39
Explicit-Value Constructor Time: : Time(unsigned init. Hours, unsigned init. Minutes, char init. AMPM) { set(init. Hours, init. Minutes, init. AMPM); //a member function } Time bed. Time = Time(11, 30, ’P’); bed. Time my. Hours 11 my. Minutes 30 my. AMor. PM P my. Mil. Time 2330 (a random value if my. Mil. Time is not set in set()) 40
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 41
§ Possible to specify default values for constructor arguments Time(unsigned init. Hours = 12, unsigned init. Minutes = 0, char init. AMPM = 'A'); Time t 1, t 2(5), t 3(6, 30), t 4(8, 15, 'P'); t 2 t 1 t 3 t 4 my. Hours 12 my. Hours 5 my. Hours 6 my. Hours 8 my. Minutes 0 my. Minutes 30 my. Minutes 15 my. AMor. PM A my. AMor. PM P my. Mil. Time 0 my. Mil. Time 500 my. Mil. Time 630 my. Mil. Time 2015 42
Copy Operations § During initialization Time t = bed. Time; t bed. Time my. Hours 11 my. Minutes 30 my. AMor. PM P my. Mil. Time 2330 Same as: Time t(bed. Time); and calls ‘copy constructor’. § During assignment t = midnight; t midnight my. Hours 12 my. Minutes 0 my. AMor. PM A my. Mil. Time 0 ‘assignment’, by default, memberwise copy of the left into the right object. 43
Other Class Operations § Accessors: "get" functions unsigned Time: : get. Minutes() const { return my. Minutes; } unsigned Time: : get. Hours() const { return my. Hours; } unsigned Time: : get. AMPM() const { return my. AMor. PM; } unsigned Time: : get. Mil. Time() const { return my. Mil. Time; } 44
§ 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')) { my. Hours = hours; my. Minutes = minutes; my. AMor. PM = am_pm; my. Mil. Time = to. Military(hours, minutes, am_pm); } else cerr << "*** Can't set time with these values ***n"; } 45
- Slides: 45