3 More About Data Structures and ADTs C
3. More About Data Structures and ADTs: C++ Data types (Read § 3. 1 & § 3. 2) C++ types an be classified as: • Fundamental (or simple or scalar): A data object of one of these types is a single object. - int, double, char, bool, complex, and the related types (unsigned, short, etc. ) - enumerations • Structured: Collections of data - arrays, structs, unions, classes, valarrays, bitsets, the containers and adapters in STL 1
Structs vs. Classes Similarities 1. Essentially the same syntax 2. Both are used to model objects with ________attributes (characteristics) represented as ______________ (also called fields or instance variables or attribute variables). Thus, both are used to process non-homogeneous data sets. 2
Differences 1. C does not provide classes; C++ provides both structs and classes. 2. Members of a struct by default are ______ (can be accessed outside the struct by using the dot operator. In C++ they can be declared to be _____ (cannot be accessed outside the struct. 3. Members of a class by default are ______ (cannot be accessed outside the class) but can be explicitly declared to be _______ 3
C Structs vs. C++ Classes (& Structs) ("traditional" vs "OOP") C++'s structs and classes model objects that have: Attributes (characteristics) represented as _________ and Operations (behaviors) represented as __________ (also called methods). Operations This leads to a whole new style of programming: object-oriented. Objects are ________, possessing their own operations — commonly called the ___________principle — rather than being passed as a parameter to an external function that operates on them and sends them back. Attributes 4
Declaring a Class Common Forms: class Class. Name { // private by default Declarations of private members public: Declarations of public members }; class Class. Name { public: //"interface" of class given first Declarations of public members private: Declarations of private members }; 5
Notes: Data members are normally placed in the private section of a class; function members in the public section. Some programmers prefer to put the private section first: - Using the default access for classes - Can omit the private: specifier Operations Function Members Data Members Attributes Other programmers put the public interface of the class first and the hidden private details last. (In the text, the latter approach is used. ) Although not commonly done, a class may have several private and public sections; the keywords private: and public: mark the beginning of each. 6
Access to Class Members A particular instance of a class is called an _______: Class. Name object_name; Private members can be accessed ___________ (except by ____ functions to be described later). Public members can be accessed ______________; to access them outside the class, one must use the __________: object_name. public_member_name A class declaration is usually placed in a header file whose name is Class. Name. h. The library is then called a class library. 7
Header file for class Time — Version 1 /** Time. h ----------------------------This header file defines the data type Time for processing time Basic operations are: Set: To set the time Display: To display the time -----------------------------------*/ #include <iostream> using namespace std; class Time { /**** Member functions ****/ public: /* Set sets the data members of a Time object to specified values. * * Receive: hours, the number of hours in standard time * minutes, the number of minutes in standard time * AMPM ('A' if AM, 'P' if PM * Postcondition: The Time object containing this function has its * my. Hours, my. Minutes, and my. AMor. PM members set to hours, * minutes, and am_pm, respectively, and my. Mil. Time to * the equivalent military time **********************************/ void Set(unsigned hours, unsigned minutes, char am_pm); 8
/* Display displays time in standard and military format using * output stream out. * * Receive: ostream out * Output: The time represented by the Time object containing * this function * Passes back: The ostream out with time inserted into it *********************************/ void Display(ostream & out) const; /***** Data Members *****/ private: unsigned my. Hours, my. Minutes; char my. AMor. PM; // 'A' or 'P' unsigned my. Mil. Time; // military time equivalent }; // end of class declaration Notes: 1. "my" in data members names is a reminder of internal ("I can do it myself") perspective. 2. const at end of Display()'s prototype makes it a ______________ which means it ______________________________ Good idea to protect data members from accidental modification. 9
3. Why make data members private? "Hidden" data members: Cannot be accessed outside class Application programs must interact with an object through its ____________ control interaction between programs and class. Application programs need not know about implementation! Implementation may______ (improve storage, simpler algorithms. etc. ) If interface is constant, programs using an object __________. What's wrong with tying application code to implementation details? A change in implementation forces a change in the application code Increased upgrade time. Increased programmer cost Decreased programmer productivity Reduced profits due to — Delayed releases/upgrades — Loss of customer confidence in software reliability Always define data members of a class as private. 10
Implementation of a Class declaration contains: • Declarations of data members • Prototypes (declarations) of function members Definitions of function members are not usually placed in class declaration Avoid cluttering up the interface Definitions placed outside the class declaration must tell compiler where the corresponding declaration/prototype is: Use the __________which has the form _______________ (the______or ____ name of Item. Name. ) This applies also to _______and ____ declared within a class. 11
Example: class Something { public: ______ const int CAPACITY = 100; typedef double Array. Type[CAPACITY]; void Print(Array. Type a, int its. Size); . . . }; . . . _______Array. Type x = {0}; for (int i = 0; i < _________CAPACITY; i++). . . void Something: : Print(Something: : Array. Type a, int its. Size) {. . . } 12
Traditionally, definitions of member functions have been put in an implementation file Class. Name. cpp corresponding to the class' header file. This is done to enforce ___________— separating the ________ of the ADT from its ______________ (Unfortunately, the class data members, which store data and are therefore part of the implementation, must be in the. h file. ) With the increasing use of _______, however, this practice is becoming less common because current compiler technology doesn't permit this split for templates — everything has to be in the same file. Thus the reason for dropping the ". h" from standard class libraries. They're really class-template libraries, and there are therefore no corresponding ". cpp" files. 13
Implementation of class Time — Version 1 // Time. cpp -- implements the Time member functions #include "Time. h /*** Utility functions ***/ /* To. Military converts standard time to military time. Receive: hours, minutes, am_pm Return: The military time equivalent Could implement this as a private class method */ int To. Military (unsigned hours, unsigned minutes, char am_pm) { if (hours == 12) hours = 0; return hours * 100 + minutes + (am_pm == 'P' ? 1200 : 0); } 14
Implementation of class Time — cont. //--- Function to implement the Set operation void _________(unsigned hours, unsigned minutes, char am_pm) { // Check _______________ 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"; // Object's data members remain unchanged } 15
Implementation of class Time — cont. //--- Function to implement the Display operation void ________(ostream & out) ______ { out << my. Hours << ': ' << (my. Minutes < 10 ? "0" : "") << my. Minutes << ' ' << my. AMor. PM << ". M. (" << my. Mil. Time << " mil. time)"; } 16
Test driver for class Time #include "Time. h" #include <iostream> using namespace std; int main() { _______________; ________________________; cout << "We'll be eating at "; ________________________; cout << endl; } Execution: We'll be eating at 5: 30 P. M. (1730 mil. time) 17
Object-Oriented Perspective Procedural: Send object off to some function for processing OOP: Send a message to the object to operate on itself. To set my digital watch to 5: 30 P. M. , I don't wrap it up and mail it off to Casio. I push a button! To display the time on my watch, I don't wrap it up and mail it off to Casio and have them tell me what time it is. I have it display the time itself, perhaps pushing a button to turn on the backlight so I can see it. 18
Notes: 1. Member functions: "Inside" an object, so don't pass object to them as a parameter. (They receive the object to be operated on implicitly, rather than explicitly via a parameter. ) Non-member functions: "Outside" an object, so to operate on an object, they must receive it via a parameter. 2. Public items must be qualified when referred to outside the class declaration: Class. Name: : Item. Name Public constants are usually declared static so they are global class properties that can be accessed by all objects of that class type rather than each object having its own copy. 3. Simple member functions: Usually specified as ________ functions — suggests to compiler to replace a function call with ___________________________________________ — saves overhead of function call. 19
Two ways to inline a class function member: 1. Prototype in class declaration; inline definition _________________________________ qualifying the name as usual. In Class. Name. h: class Class. Name { public: Ret. Type Simple. Fun(param_list); . . . }; //prototype _____ Ret. Type Class. Name: : Simple. Fun(param_list) {. . . } // definition 2. Put function’s _____ (instead of prototype) _________________— compiler will treat it as inlined. 20
Class Invariant: A condition (boolean expression) that ensures that the _____________________ Example: 1 < my. Hours < 12 && 0 < my. Minutes < 59 && my. AMor. PM == 'A' or 'P' && 0 < my. Mil. Time < 2359 Operations that modify data members must __________________ Then other operations can be sure data members have valid values. How? 1. Use an if statement — see Set() 2. Use _____(class_invar); (must #include <cassert>) true false continue execution halt execution and display error message 21
3. _____________that the calling function can ____ and take appropriate action: //----- Function to implement the Set operation ----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')) {. . . } else { char error[] = "*** Illegal initializer values ***n"; ______ error } } 22
To catch this exception, a calling function might contain: ____ { meal. Time. Set(13, 30, 'P'); cout << "This is a valid timen"; } _________________ { cerr << "ERROR: " << bad. Time << endl; exit(-1); } cout << "Proceeding. . . n"; When executed, the output produced will be ERROR: *** Illegal initializer values *** 23
Class Constructors Constructing an object consists of: (1) __________ for the object, and (2) ______ the object. In our example, after the declaration Time meal. Time; memory has been allocated for object meal. Time and it's data members have some default (perhaps "garbage") initial values. Need to: Specify initial values for meal. Time Provide default values to be used if no initial values are specified. This is the role of a class' ________. (Later, it will also allocate memory. ) 24
Class Constructors - Properties 1. Names are always the same as the class name. 2. Initialize the data members of an object with default values or with values provided as arguments. 3. Do not return a value; have no return type (not even void). 4. Often simple and can be inlined. 5. Called ________________________. 6. If no constructor is given in the class, _____________________________which allocates memory and initializes it with some default (possibly garbage) value. A default constructor is one that is used when the declaration of an object contains _______________: Class. Name object_name; An _____________ constructor is used for declarations with initial values: Class. Name object_name(list-of-init-values); 7. If we supply a class constructor, we must also provide a 25 ______________ or we can't use first kind of declaration.
Constructors for Time class In Time. h class Time { public: /* --- Construct a class object (default). * Precondition: A Time object has been declared. * Postcondition: Data members initialized to 12, 0, 'A', and 0. ********************************/ ___________ /* --- Construct a class object (explicit values). * Precondition: A Time object has been declared. * Receive: Initial values init. Hours, init. Minutes, and * init. AMPM * Postcondition: Data members initialized to init. Hours, init. Minutes, * init. AMPM, & correspoding military time *****************************/ _____________________ __________. . . // other member function prototypes private: /***** Data Members *****/. . . }; // end of class declaration 26
Constructors for Time class - Implementation In Time. h, after class declaration: _____________ { my. Hours = ____; my. Minutes = ____; my. AMor. PM = _____; my. Mil. Time = ___; } In Time. cpp: ________(unsigned init. Hours, unsigned init. Minutes, char init. AMPM) { // Check class invariant assert(init. Hours >= 1 && init. Hours <= 12 && init. Minutes >= 0 && init. Minutes <= 59 && (init. AMPM == 'A' || init. AMPM == 'P')); my. Hours = _________; my. Minutes = ________; my. AMor. PM = ________; my. Mil. Time = To. Military(init. Hours, init. Minutes, init. AMPM); } 27
Testing #1: Time _______________, _______________; //default constructor //explicit-value constructor Create and initialize 2 Time objects: meal. Time. Display(cout); cout << endl; bed. Time. Display(cout); cout << endl; Execution: 12: 00 A. M. (0 mil. time) 11: 30 P. M. (2330 mil. time) 28
Constructors for Time class — Default Arguments Can combine both constructors into a single constructor function by using ____________: Replace constructors in Time. h with: /*--- Construct a class object. Precondition: A Time object has been declared. Receive: Initial values init. Hours, init. Minutes, and init. AMPM (defaults 12, 0, 'A') Postcondition: Data members initialized to init. Hours, init. Minutes, init. AMPM, & correspoding military time. */ Note: Any parameter with default argument must appear after all parameters without default arguments. 29
Testing: Time meal. Time, t 1(5), t 2(5, 30), t 3(5, 30, 'P'); Creates 4 Time objects: meal. Time. Display(cout); cout << endl; t 1. Display(cout); cout << endl; t 2. Display(cout); cout << endl; t 3. Display(cout); cout << endl; Execution: 12: 00 A. M. (0 mil. time) 5: 00 A. M. (500 mil. time) 5: 30 A. M. (530 mil. time) 5: 30 P. M. (1730 mil. time) 30
Copy Operations Two default copy operations are provided: 1. Copy in _______ (via _____________) 2. Copy in _______ (via _____________) Each makes a ________________ allocated to the data members of the object. 31
Examples: Both: 1. Allocate memory for t 2. Copy data members of bed. Time so t is a copy of bed. Time In contrast: _____________ calls the _____________ to construct a (temporary) Time object and then copies it into t. What about Time t = Note: These are _________; a default ___________ is called. Time t = 3; ? 32
There is a default copy operation for assignment. Example: t = meal. Time; copies the members of meal. Time into t, replacing any previous values: 12 0 A 0 It returns _____________________ 33
Access Member Functions Data members are private: they cannot be accessed outside the class. To make the values stored in some or all of these members accessible, provide______ (or extractor) member functions Example: To provide access to my. Hours of class Time. (Access for the remaining members is analogous. ) simply retrieves and returns the value stored in a data member inline, because it's simple prototype (and define) as a const function Add in Time class declaration /* Hour Accessor * Return: value stored in my. Hours data member of * Time object containing this function */ ____________________ 34
Add below Time class declaration inline unsigned Time: : Hour() const {___________} Testing: Time meal. Time; . . . cout << "Hour: " << meal. Time. Hour() << endl; Execution: Hour: 12 35
Output and Input Add output operation(s) to a class early so it can be used for debugging other operations. Example: overload operator<< for a Time object Instead of: cout << "We'll be eating at " ; ____________________ cout << endl; we can write: cout << "We'll be eating at " ____________________ 36
Overloading operators In C++, operator D can be implemented with the function operator. D(). If a member function of a class C, and a is of type C, the compiler treats a D b as _____________ If not a member function of a class C, the compiler treats a D b as _____________ 37
Overloading Output Operator << Can operator<<() be a member function? ______, because the compiler will treat cout << t as ____________ which means that operator<<(const Time &) would have to be a __________________(or cout be of type Time) and we can't (or don't want to) modify standard C++ classes. Putting the prototype ostream& operator<<(ostream & out, const Time& t); inside our class declaration producs a compiler error like: 'Time: : operator <<(ostream &, const Time &)' must take exactly one argument 38
Why is out a reference parameter? So corresponding actual ostream argument gets modified when out does. Why is t a const reference parameter? Avoid overhead of __________________ Why is return type ostream & (a reference to an ostream)? Else a _________ is returned. Why return out? So we can _____________. Since << is ____-associative: cout << t 1 << endl << t 2 << endl; operator<<(cout, t 1) << endl << t 2 << endl; first function must return _______ << endl << t 2 << endl; operator<<(cout, endl) << t 2 << endl; _______ << t 2 << endl; . . . 39
Overloading << for a Class Method 1: Put definition in. h file, after class declaration, and have it _____________________. Inline it, because it's simple. . } // end of class declaration. . . /* operator<< displays time in standard and military format. Receive: ostream out and Time object t Output: time represented by Time object t Pass back: ostream out with t inserted into it Return: out */ _______ ostream & operator<<(ostream & out, const Time & t) { } 40
Method 2: Define operator<<()outside the class declaration as a ________ function and: (i) use _________ to display data members, or (ii) declare it to be a _____in the class declaration. In class declaration /* doc. as before */ _____ ostream & operator<<(ostream & out, const Time & t); Outside class declaration (in. cpp file) ostream & operator<<(ostream & out, const Time & t) { } out << << << return t. my. Hours << ': ' (t. my. Minutes < 10 ? "0" : "") t. my. Minutes ' ' << t. my. AMor. PM << ". M. (" t. my. Mil. Time << " mil. time)"; out; 41
Friend Functions A function that a class declares as a friend is a ________ function to which the class has granted permission to ____________________. Note: Because a friend function is not a function member: Don't ______________ with class name and scope operator (: : ). Don't put ______ in definition. It receives the object on which it operates as a parameter. It uses the dot operator to access the data members. 42
To add an input operator to our Time class, we proceed in much the same way as for output. We could either: 1. Add a member function Read. Time() that reads values and stores them in the data members of a Time object; then call it from nonmember function operator>>(). 2. Declare operator>>() to be a friend function so that it can access the data members of a Time object and store input values in them. Is one of the two methods for input/output preferred? We'll see later when we study inheritance and polymorphism that the first method is preferred (or perhaps required). 43
Relational Operators (<) Specification: Receives: Two Time objects Returns: True if the first object is less than the second; false otherwise. Should operator<() be a member function? Internal perspective: I compare myself with another Time object and determine if I am less than that other object External perspective: Two Time objects are compared by an external function to determine if the first is less than the second. OOP: "I-can-do-it-myself" principle ( objects self-contained): Use member functions whenever possible. Rephrased specification: Receives: A Time object (and the current object implicitly) Returns: True if I (the Time object containing this function) am less than the Time object received; false otherwise. 44
// Internal perspective : Add to Time. h class Time { public: // member functions. . . /***** Relational operators *****/ /* operator< determines if one Time is less than another Time * Receive: A Time t (and the current object implicitly) * Return: True if time represented by current object is < t. */ bool operator<(const Time & t) const; . . . }; // end of class declaration inline bool Time: : operator<(const Time & t) const { return my. Mil. Time < t. my. Mil. Time; } However. . . 45
Caveat re Operator Overloading Internal perspective may lead to seeming inconsistencies: Example: Suppose a and b are objects of type class C. a < b okay? Yes, equivalent to _____________ b < a okay? Yes, equivalent to _____________ a < 2 okay? _____, if there is a __________________, since this is then equivalent to _____________ 2 < a okay? ____, equivalent to __________which is meaningless. May confuse an application programmer to support a < 2 but disallow 2 < a. probably best to use friends here. 46
Overloaded Operator as Friend External perspective: (Permits a < 2 and 2 < a , if 2 can be promoted) class Time { public: // member functions. . . /* operator< * Receive: Two Times t 1 and t 2 * Return: True if time t 1 is less than time t 2/ */ __________________________________ ); . . . }; // end of class declaration inline bool Time: : operator< (const Time& t 1, const Time& t 2) {return ___________________; } Or don't use friend and compare values obtained by accessors. 47
Adding Increment/Decrement Operators Specification: Receives: A Time object (perhaps implicitly) Returns: The Time object with minutes incremented by 1 minute. Question: Should it be a member function? _____ Add to Time. h: /***** Increment operator *****/ /* --- Advance() increments a Time by 1 minute. Postcondition: The Time object has its minutes incremented by 1. ------------------------*/ _________________ 48
Add to Time. cpp: //----- Function to implement Advance() ----void Time: : Advance() { my. Minutes++; my. Hours += my. Minutes / 60; my. Minutes %= 60; my. Hours %= 12; if (my. Mil. Time == 1159) my. AMor. PM = 'P'; else if (my. Mil. Time == 2359) my. AMor. PM = 'A'; // else no change my. Mil. Time = To. Military(my. Hours, my. Minutes, my. AMor. PM); } 49
++ We could replace Advance() with overloaded operator++(). Question: How do we distinguish between prefix ++ and postfix ++? Solution: In C++, when the Compiler encounters: It looks for: Prefix ++: Postfix ++: (which is not used in the definition. ) 50
Redundant Declarations Class Time might be used in different programs, libraries, etc. , so it could be included several times in the same file e. g. , Program needs Time class, so it #includes "Time. h" Program also needs library Lib, so it #includes "Lib. h". . . but Lib. h also #includes "Time. h" This can cause "redeclaration" errors during compiling. How do we prevent the declarations in Time. h from being included more than once in a file? 51
Conditional Compilation Wrap the declarations in Time. h inside preprocessor directives. (Preprocessor scans through file removing comments, #including files, and processing other directives (which begin with #) before the file is passed to the compiler. ) #ifndef TIME #define TIME : : #endif ¬¾Usually the name of the class in all caps The first directive tests to see whether the identifier TIME has been defined. If not defined: Proceed to second directive ( define TIME ) Continue to the #endif and beyond. If defined: Preprocessor removes all code that follows until a #elsif, #else, or #endif directive encountered. 52
- Slides: 52