CMSC 202 More C++ Classes 1 Announcements • • • • Project 1 due midnight Sunday 2/25/01 Quiz #2 this week Exam 1 Wednesday/Thursday Project 2 out Monday March 5th 2 const • Use “const” (constant) whenever possible • Supports the concept of “least privilege” • Objects may be const • Member functions may be const • Parameters may be const 3 const Objects • We’ve already seen const float PI = 3.14; that creates a float that cannot be changed • We can also create const objects const Time noon(12, 0, 0); – noon is not modifiable 4 const member functions • Not all member functions modify the object – Accessors – Others later • And so should be declared ‘const’ int GetHour ( void ) const; • The compiler doesn’t “know” that GetHour( ) doesn’t modify the Time object 5 (non-)const objects and (non-)const member functions • Rules of engagement: – const member functions may be invoked for const and non-const objects – non-const member functions can only be invoked for non-const objects – you cannot invoke a non-const member function on a const object • Constructors and Destructors may not be const 6 Modified Time class Time { public: Time (int h = 0, int m = 0, int s = 0 ); void InitTime (int h, int m, int s); void PrintMilitary ( void ) const; void PrintStd ( void ) const; void Increment ( void ); ….. 7 Modified Time (cont’d) // mutators void SetHour (int h); void SetMinute (int m); void SetSecond (int s); // accessors – should be const int GetHour (void) const; int GetMinute (void) const; int GetSecond (void) const; 8 Modified Time (cont’d) private: int hour; int minute; int second; }; 9 int main ( ) { Time t1 (2, 4, 7); const Time noon (12); cout << “Initial Military Time for t1 is :” ; t1.PrintMilitary ( ); // okay cout << endl; cout << “Noon in Military Time:” noon.PrintMilitary ( ); // okay cout << endl; cout << “Increment Noon:” ; noon.Increment ( ); // compiler error cout << endl; } 10 Non-member functions should have const reference parameters wherever possible • Rules of engagement: – Non-const objects may be passed to const and non-const arguments – Const objects may only be passed to const arguments • Bottom line – you can’t pass a const object to a non-const argument 11 Non-member PrintTime void PrintTime (Time& t) { cout << t.GetHour( ) << “:”; cout << t.GetMinute( ) << “:”; cout << t.GetSecond( ); } 12 Calling PrintTime void PrintTime (Time& t); • Callable using t1 – PrintTime ( t1 ); • Not callable with noon – PrintTime (noon); • Why the difference? 13 A better PrintTime • Since PrintTime( ) doesn’t modify the Time object passed to it, the argument should be const void PrintTime (const Time& t) • Doing so doesn’t change the code, but now does allow noon to use the function PrintTime (noon); 14 A subtlety • What happens if ‘noon’ is passed to the new PrintTime ( ) function, but the accessors are not const? 15 Composition • Sometimes objects are used as members of other objects. For example, an AlarmClock class may include a Time object. • This is known as “composition” or “aggregation”. • Member objects are constructed automatically • A common form of code reuse. 16 AlarmClock class AlarmClock { public: AlarmClock ( ); void SetAlarm (int h, int m, int s); ... private: ... void ring( ) const; Time currentTime; const Time alarmTime; } 17 “this” and that • Every object has access to it’s own address through a pointer called this. • The this is implicitly used to reference both data members and member functions of an object… it can also be used explicitly. • This is passed implicitly as the first argument of every (non-static) member function 18 A “this” example // should have error checking void Time::SetMinute (int m) { this->minute = m; } • More valuable later 19 Dynamic Memory Allocation • In C we used malloc int *intp; intp = (int *)malloc (sizeof(int) ); • In C++ we use new int *intp; intp = new int; or intp = new int (7); 20 Allocating Dynamic Arrays • Again, in C we used malloc: int *ip2; int *ip2 = malloc (50 * sizeof(int)); • In C++ we use new and the size int *ip2 = new int[10]; 21 Freeing Dynamic Memory • In C we used free free (intp); free (ip2); // for a single int // or an array • In C++ we use delete delete intp; // for a single int delete [ ] ip2; // for an array 22 A simple class that uses dynamic memory Class Array { public: Array (int size = 100); void putElement (int x); int getElement (void); .... private: int *theArray; } 23 Array Constructor • Allocate the memory in the constructor Array::Array (int size) { theArray = new int [size]; } 24 The Array Destructor • Free the memory in the destructor Array::~Array ( ) { delete [ ] theArray; } 25 Good Programming Practices • Use const wherever possible • Declare member functions that do not change the object as const • Avoid friends • Use member initialization lists • Allocate dynamic memory only in the constructor • Delete dynamic memory only in the destructor 26