Class Implementation

Encapsulation

Classes are full-fledged data types like int, float and double. As we've seen, you can create variables of a class type (an object). You can also pass the them to functions, and a function can return a value of a class type. You can use a class just like any other data type.

A class models a single entity -- one Person, one Car, one Book, one Library.

Classes are used to implement user-defined ADTs. These are classes whose external behavior is known to the class user, but whose internal implemenation is hidden.

But a data type is more than just data..... it also has a set of associated operations. Built-in types like int, float, char have opearations such as add, subtract and multiply. Since the details of these operations are hidden, we can consider the built-in data types to be "Abstract Data Types" (ADTs).

To accomplish this goal, we need a mechanism to hide the details of the class implementation from the class user.

Recall the initial DayOfYear class definition from the text.

class DayOfYear { public: void Output( ); int m_month; int m_day; }; As shown in the example code, the class user is able to manipulate the data members of the class. Nothing is hidden from the class user.

Now consider this new improved (but not yet perfect) definition of the DayOfYear class. This definition is adapted from Display 6.4 of the text.

class DayOfYear { public: void Input( ); void Output( ); void Set( int newMonth, int newDay ); void Set( int newMonth ); int GetMonthNumber( ); int GetDay( ); private: int m_month; int m_day; }; Note the keywords public and private.

No item that follows the keyword private can be directly referenced by name in any code except the implementations of the class member functions. Attempting to do so results in a compiler error. The compiler enforces the hiding of class details through the use of the keyword private.

Items which follow the keyword public may be referenced in any code, just like members of a struct. Good programming practice, and a REQUIREMENT in this course is that all data members of a class must be declared private.

C++ implements encapsulation by allowing data members to be declared as private. A private datat member will only be accessible to functions that are members of that class and to functions and classes explicitly granted access permission by the class ("friends" -- more on this later).

Member Functions

Because the data members are now private, public member functions are writtten to provide indirect access to the data for the class user.

Member functions that allow the class user to retreive the value of a private data member are known as accessor -- GetDay( ), GetMonthNumber().

Member functions that allow the class user to change the value of a private data member are known as mutators -- both Set( ) functions.

Other member functions generally provide support for the ADTs operations and are often referred to as services -- Input( ), Output( ) As we'll see next time, other special methods are also provided.

Member Function Guidelines

  1. Like any well written function, each class' member function should perform just one task and do it well. Private functions may be written and called from the public function to allow proper modularity.
  2. No class member function should perform input from or output to the application user unless that is the function's explicit purpose.
    For example, a class that models a Person would likely have an accessor named GetName( ). This function allows the class user access to the data member which contains the Person's name. It DOES NOT prompt the application user to input the Person's name.
  3. Although member functions have direct access to private data members, your code should use accessors and mutators whenever available. Doing so further limits the scope of code that needs changed in the future.
  4. Proper passing of parameters is vital for efficiency of your program. Pass objects by reference whenever possible (almost always).
  5. Also see the guidelines for the use of const.

Example code

This is display 6.4 (page 244) from the text, modified for CMSC 202 coding standards. What changes, if any, would you recommend for this code? #include <iostream> #include <cstdlib> using namespace std; class DayOfYear { public: void Input( ); void Output( ); void Set(int newMonth, int newDay); void Set(int newMonth); int GetMonthNumber( ); int GetDay( ); private: int m_month; int m_day; }; int main( ) { DayOfYear today, bachBirthday; // input and echo today's date cout << "Enter today's date:\n"; today.Input( ); cout << "Today's date is "; today.Output( ); cout << endl; // set and output JSB's birthday bachBirthday.Set(3, 21); cout << "J. S. Bach's birthday is "; bachBirthday.Output( ); cout << endl; // output special message if ((today.GetMonthNumber( ) == bachBirthday.GetMonthNumber( )) && (today.GetDay( ) == bachBirthday.GetDay( ) )) cout << "Happy Birthday Johann Sebastian!\n"; else cout << "Happy Unbirthday Johann Sebastian!\n"; return 0; } //----------------------------- // DayOfYear mutator functions //----------------------------- //------------------------------ // Set // PreConditions: // 1 <= newMonth <= 12 // 1 <= newDay <= 31 // PostConditions: // day of year changed to user supplied values //------------------------------ void DayOfYear::Set(int newMonth, int newDay) { if ((newMonth >= 1) && (newMonth <= 12)) m_month = newMonth; else { cout << "Illegal month value! Program aborted.\n"; exit(1); } if ((newDay >= 1) && (newDay <= 31)) m_day = newDay; else { cout << "Illegal day value! Program aborted.\n"; exit(1); } } //------------------------------ // Set // PreConditions: // 1 <= newMonth <= 12 // PostConditions: // day of year changed to 1st day // of new month //------------------------------ void DayOfYear::Set(int newMonth) { if ((newMonth >= 1) && (newMonth <= 12)) m_month = newMonth; else { cout << "Illegal month value! Program aborted.\n"; exit(1); } m_day = 1; } //----------------------------------- // DayOfYear accessor functions //----------------------------------- //------------------------------------ // GetMonthNumber // PreConditions: none // PostConditions: // returns 1 for Jan, 2 for Feb, etc //------------------------------------- int DayOfYear::GetMonthNumber( ) { return m_month; } //------------------------------------ // GetDay // PreConditions: none // PostConditions: // returns day of month //------------------------------------- int DayOfYear::GetDay( ) { return m_day; } //----------------------------------------- // Input // PreConditions: none // PostConditions: // month and day input by user and // validated. invalid input aborts program // valid input changes month and day //----------------------------------------- void DayOfYear::Input( ) { cout << "Enter the month as a number: "; cin >> m_month; cout << "Enter the day of the month: "; cin >> m_day; if ((m_month < 1) || (m_month > 12) || (m_day < 1) || (m_day > 31)) { cerr << "Illegal date! Program aborted.\n"; exit(1); } } //----------------------------- // Output // PreConditions: // 1 <= m_month <= 12 // PostConditions // Date output using day and name of month //----------------------------- void DayOfYear::Output( ) { switch (m_month) { case 1: cout << "January "; break; case 2: cout << "February "; break; case 3: cout << "March "; break; case 4: cout << "April "; break; case 5: cout << "May "; break; case 6: cout << "June "; break; case 7: cout << "July "; break; case 8: cout << "August "; break; case 9: cout << "September "; break; case 10: cout << "October "; break; case 11: cout << "November "; break; case 12: cout << "December "; break; default: cout << "Error in DayOfYear::Output. Contact software vendor."; break; } cout << m_day; }


Last Modified: Monday, 28-Aug-2006 10:15:53 EDT