This test is a 50 minute written exam designed to explore introductory concepts of object oriented programming and the Standard Template Library. There will be both conceptual questions about overall concepts (the forest), and nitty-gritty questions about the C++ and the Standard Template Library (the trees). The test will cover only chapters 2 (Classes and Object-Oriented Programming), Chapter 6.3 (Iterators), and Chapter 7 (The string Data Type).
Below are a list of what I see are the important concepts. Questions on the test will focus on these concepts, but I will expect that you should be able to illustrate each concept with nitty-gritty C++ examples.
- We first discussed the concept of a class and the C++ class construct. I discussed in class how we:
- first design our application as a collection of objects,
- then implement the design objects as a set of classes,
- then instantiate those classes as a set of interacting implermentation objects.
- We noted that a class is both a conceptual grouping of a collection of objects (a collection of "people"), and a C++ mechanism that provides services to any "person" that needs to execute operations on itself.
- A class consists of constructors (and destructors, later discussed in chapter 7), member functions, and operators. An important concept in C++ is how we think of operations performed on objects. When we execute an operation on an object, we say we "send a message to that object to execute an operation on itself". Note that since an operation is always executed on behalf of an object, the data members of the object are accessed inside that operation without explicitly referring to the object name.
- We discussed the construction of an interactive card game, War. You should be familiar with the structure of that implementation. Paricularly you should understand how the classes are defined, how the objects are instantiated, and how the objects interact.
- The idea of accessor and mutator functions is simple. Accessor functions only observe the state of the object and report back information about the object. The length of a string is an example of an accessor function. Mutator functions set or modify the state of the object. Adding a substring to a string or adding a card to a deck is an example of a mutator function.
- A number of small details about the War game were important to us:
- A class is defined using both a public and (possibly a) private part, and how the public part is visible to the class user, whereas the private part is only accessible by the class member functions. Note specifically that the data items of the class card were all public, and therefore needed no member functions to access them. On the other hand, the data items of the class deck were protected, and therefore did need member functions to access them.
- Operators can be re-defined to provide new meaning. For example, the << operator was "overloaded" (redefined) to provide the output of a card. Note that since the data members of a card were public, the operator did not need to in any way be part of the class card. It could "stick it's hand" inside of a card without being part of the class definition. Recall that in chapter 7 the string operators did need to be related to the string class, by either being defined directly in the class or as friends of that class. This way they would be granted permission to reach inside of the protected parts of an object.
- The concept of an iterator and it's use with the Standard Template Library generic algorithms was introduced. Specifically we used the generic algorithm random_shuffle. In order to use this routine we had to provide a begin and end iterator (in this example in the form of two pure C++ pointers), and a reference to a function that would be applied to each element in the card deck array. You should revisit this example now that you have thought about and seen example of iterators in later chapters. It will make a bit more sense why the library designers do it this way - they want to achieve maximum reuse of the generic algorithms across a variety of library component classes.
- Look carefully at section 2.5 - "The Game Itself". It is your first introduction to a main program that instantiates the deck and player, and player card objects. Note that the 52 cards are initially instantiated inside of the Deck constructor, and therefore happen as a by-product of the deck instantiation.
- Important! - I stressed the importance of viewing each class from three perspectives - the usage of the class, the specification of the class, and the implementation of the class. It's extremely important to remember where you are in an implementation. For example:
- A class definition itslf is an example of a specification.
- The operations provided with the class (implemented by referring to the class with the :: name reference) package the implementation of each class operation. The only exception to this is when short implementations are provided directly in the class definition in the form of in-line implementations.
- Classes are used when (1) objects are instantiated in main programs or using classes (the war main program or the deck class implementation that uses cards)), or when (2) objects are manipulated in those same main programs or using classes.
- Remember when I used my two handed visualization of a specification and it's implementation (one hand over the other). I did this specifically with the string specification, implemented with a C-style array of characters called "buffer". I did this to help us keep the two points of view, specification and implementation, separate in our minds.
Chapter 7 provided us with an introduction to strings, one of the basic and most useful Standard Template library data types.
- Our three perspective model of classes should be applied carefully here. In the chapter we first looked at a number of examples illustrating string usage. We did this primarily to better understand the string class definition (the specification) in order to then better understand how each operation should be implemented. This model of chapter layout will be repeated for subsequent component types in the text.
- Know how strings are used, and be prepared to write or understand a simple program using strings. Above all, know the reasons why the Standard Template Library designers felt it necessary to provide a string data type in a language that already had a basic string type in the form of operations on C-style arrays.
- The palindrome example provided yet another example of the use of a generic algorithm - reverse. Note how it was used, by using the begin and end iterator operations provided by the string class. As we noted in subsequent classes, this same reverse algorithm could be used with other StL components.
- Important! Note on pg. 127 an example implemention of a generic algorithm - transform. We subsequently discussed how the *, ++, and = operators were all iterator operations by each component type that provides an iterator.
- The split algorithm gave us our first glimpse into the template concept of chapter 8 (using lists). The template concept won't be on the exam.
- In order to prepare ourselves to implement the string component, we needed to understand the C-style pointer. Know what it is and how to manipulate it (pg. 124 of the text).
- We spent a number of classes discussing the usage of the string operations:
- A number of different overloaded constructor operations were provided.
- Character access operations were provided to mimic our basic model of array access.
- StL strings can be tested for length and resized larger and smaller. They can also be assigned larger or smaller strings, or appended with other strings. Storage will be adjusted accordingly.
- Substring search and manipulation operations are provided.
- A number of generic algorithms are provided by the StL that are useful for strings as well as other similar StL components.
- After fleshing out the string specification with examples and discussion, we then spent a number of classes on the implementation. This implementation presented it's own unique set of problems, primarily focused on how to manage the dynamic storage allocation and deallocation of string buffers, and how to implement string operators as friends.
- In preparation for implementing the string class, we discussed the C++ provided dynamic storage "heap" along with it's operations new and delete. We encapsulated the use of new and delete inside of a general purpose procedure resize, and then used this procedure in most of the operations requiring string creation or resizing. The delete operation was also used in the string destructor.
- We then decided on a string implementation in which string storage would be reallocated by the heap whenever a string was resized larger. The ramifications of this were that there might be extra space lying around inside a string if it were ever resized smaller.
- Note how we implemented the string operators, specifically the character access operator [ ] and the comparison operators (as friends).
- Note also how we implemented the string iterator directly as a pointer. Remember the important discussion about how iterators are not pointers, although they could be implemented with pointers. In this case we implemented them with pointers, and the begin and end operators have simple implementations.
After going through a number of examples in both the War example and string implementation example, we then revisited the concept of an iterator. Iterators are provided by the Standard Template library designers in an effort to provide an abstraction that looks like a pointer and feels like a pointer (to a generic algorithm), but that might not be implemented as a pointer.
Specifically, we went through the find generic algorithm, and noted that there are three requirements for an iterator - it must provide the =, *, and ++ operators (assignment, dereferencing, and incrementing). Optionally it may also provide a decrement operation.