Comp 272 Study Guide and Sample Exam Dordal Feb 20, 2004 Exam is Monday, Feb 23 The exam will be OPEN BOOK, although we have not been following the book closely. Still, the book can serve as a C++ reference as needed. Things to study: Chapter 2: you should be familiar with essentially everything here, HOWEVER in general I don't expect perfect syntax on an exam. The important concepts are probably use of cin/cout and String. Another early concept (covered awkwardly in the book) is the standard template vector class, eg vector A(30); Chapter 3: Basics of Rectangle and RectShape classes 3.9: free functions, and basic overview of OOD Chapter 4: if, while, etc (probably familiar from Java) Chapter 5: basics of writing classes; how to declare classes ctors Rectangle Accumulator also: member initialization list in ctors importance of default ctors Chapter 6 function reference parameters, with & (section 6.9) accessors, mutators, field accessors, field mutators, const Book's Date class (used in Calendar) Chapter 8 8.2 and 8.3 on OOD and building a Calendar class from existing Day and Date classes. Chapter 10 basics of C++ pointers (10.1) arrays and incrementing pointers (10.2) basics of dynamic memory and new (10.3; ignore "delete") C strings as char* (mostly not in book) Chapter 12 Basics of inheritance (12.1) static v dynamic inheritance virtual functions and Shapes hierarchy (12.4 and some 12.5) Be familiar with the arguments for keeping data private, and "common sense" rules for class design (eg keep the design focussed on one concept). Here is a reasonable list of design concerns: Classes should have: * focus! (ie, classes should be "coherent") A class should be about one thing You should be able to state what a class is about in a single sentence. * consistent operations both syntactically and semantically disaster: op1(month,day), op2(day,month) (inconsistent order) don't use inconsistent names like get_day() and then month() * complete operations A class interface should allow most (relevant!) things But note two Rectangle classes! "relevant" means "relevant for the problem domain" * class types are the norm; reconsider long member lists of primitive types example: fname, mi, lname, streetaddr, city, state, zip * primitive operations are better in *many* cases bool List::advance(int & value) versus: bool List::atend(); void List::advance(); int List::getcurrent(); * sometimes we break these rules for convenience Review both the CRC card method for describing class relationships and the UML-diagram approach. Bear in mind, however, that there won't be enough time on the exam for a significant question on complex class relationships. Know the basics of having a virtual function do different things in the base class and derived class, and know how to use pointers to class objects to achieve this feature. One important technique was calling the base class ctor in the member initialization list. ================================== Here are a few sample questions. Some have been used on past exams; others were rejected as being too hard! Answers will be posted. 1. Consider the following operations in a class Date: class Date { public: Date(int month, int date, int year); String tostring(); void advance(int ndays); // advances the date by a given number of days }; (a). Modify the design of the class so advance returns a new date, instead of modifying the existing date. Declare the revised version with all applicable uses of "const". (b). Suggest a reasonable collection of accessors that would give you ways to access and use the date. You should be able to convert the entire date to a string, and also extract the year, day, and month fields. (c). Discuss why it would be a bad idea for the Date class to make any of its internal fields public. Try to give at least two fundamental reasons. 2. (a). Consider a banking system, with classes for checking accounts and savings accounts. The Checking_Account class has member functions withdraw(Money amt), deposit(Money amt), and writecheck(Money amt). The Savings_Account class has member functions withdraw and deposit and also AddInterest(double interest_rate). Arrange these classes in a suitable inheritance hierarchy. Introduce a common base class with the appropriate operations. Do not implement any functions; just show what gets declared in what class! 3. Write a C++ function vsearch(v, x, found) to search a vector v of doubles for a given value x. If x is found at position v[i], then i is to be returned and the actual parameter corresponding to found (of type bool) is to be set to "true"; if i is not found then set found=false. Note that found must be a reference parameter (declared with &). 4. (a). Draw class diagrams for the voicemail system, modified so that MailAccount does all user interaction and makes appropriate calls to a class member of type MailData to get things done. Specifically, show the relationships between MailData, MailAccount, InputReader, and Message. (b). Our implementation derived AdminMailbox from Mailbox. Yet the MailSystem::process_dialing function still explicitly checked for extension 9999 to determine if a mailbox was an Admin box or not (in other words, no "polymorphism" was used). Given this, what was the advantage (if any) to using inheritance here? 5. Consider the following outline of a list interface. Assume the list are of objects of type X. Note that this interface maintains a "current" element of the list; the internal "cursor" is in effect a pointer to the current element. class listX { public: start() // set an internal "cursor" to start of list next(); // advance cursor to next element set(); // set current element to a new value get(); // return current element add(); // add new element after current cursor position addbefore(); // like add, but inserts new element in front of current delete(); // deletes current element islast(); // true if current element is last element length(); // return length of list ... } (a). Provide parameter lists for all the above, indicating which member functions are const. Also indicate which member function parameters are const (ie where the actual parameter will not be modified). (b). Explain why both add() and addbefore() are necessary; that is, give an example of something that can be done with add() but not addbefore() and something that can be done with addbefore() but not with add(). 6. [This one is a little arcane, but at heart it's just about class interfaces again.] The list class in problem 5 has a disadvantage in that there can be at most one cursor. Implementing a linked-list class with public pointer fields is that one way to support multiple cursors (pointers) into the same list, but the price is that a critical data field is now public, which ties one to a specific implementation, and causes a loss of some type safety. One way to have the best of both worlds is to implement "external iterators"; that is, one has a class List and also a class ListCursor. A ListCursor object represents a pointer into a linked list; alternatively, if the List is implemented as an array, then a ListCursor represents an array index value. All list operations that refer to the "current" element would now be made in terms of a ListCursor object. The class ListCursor would be able to access the private: data of class List, either because ListCursor was declared inside class List, or was declared to be a "friend" class. Specify the interface for List and ListCursor, and indicate with a comment what each operation does. As a hint, a constructor for a ListCursor is specified; it takes a List reference and sets the ListCursor to mark the first element of the list. class List { }; class ListCursor { friend List; public: ListCursor (List & L); // Sets the listcursor to point to head of L }; 7. Define a class Complex (for complex numbers). Do *not* implement any of the operations, though! A complex number should have two data fields, _real and _imag, of type double. You *should* implement the following constructors, though: (a) Complex (double, double); // set _real and _imag (b) Complex (double) // set _real; let _imag = 0; (c) default ctor 8. Suppose one has the following declarations: int x = 3; int * px = &x; int * q = new int(4); (*px)++; (*q) += 3; px = q; (*px)+=1; What are the values of x, *px, and *q? How would this problem appear if references were used instead? 9. Suppose one has class Base { private: int _x; public: Base(int x) : _x(x) {} virtual int f() {return _x;} }; class Deriv : public Base { private: int _y; public: Deriv(int x, int y) : Base(x), _y(y) {} virtual int f() {return Base::f() + _y;} }; Base * b = new Base(3); Base * bd = new Deriv(4,5); Deriv* d = new Deriv(7,8); What is the output: cout << b->f() << endl; cout << bd->f() << endl; cout << d->f() << endl;