CS51 Midterm 2, Spring 2008 Answer Key 1. A. more efficient to pass by const reference in most cases B. a reachable state is recognizable by the parser (ie., it was generated by an execution of the grammar) C. overloading an operator is customizing the behavior of an operator for a certain class; it can be useful for making function calls more succint/easy to read D. Class Class::operator+(Class c, int i); is an example of how you might overload the + operator for a class E. A pure virtual function is a function that has no implementation--it is just a placeholder, requiring that subclasses implement this function. F. virtual void foo() = 0; G. There is a difference in output: f1(c) won't print anything, f2(c) will print pd ccd H. 1 2 3 All three classes share the same static variable--count. Thus, when each new instance is created, we increment the same count variable, because the base constructor keeps getting called. 2. A. a) lexer can catch this--CS51 isn't something the the lexer should need to recognize as a token b) parser can catch this; it will lex fine, but the grammar presumably doesn't allow for a + that doesn't have numbers on both sides c) 5 / (1 - 1) You have to do some calculation here before you realize that you are going to get a divide by zero B. a) You could modify the grammar to have a rule for if. You'd also need to change the lexer to recognize the "if" token. b) Pro: good to catch errors earlier (at "compile" rather than "run") Con: a lot more complicated--need to change the grammar, lexer implementation; you're going to need to do the work for checking the number of arguments to apply anyway, so you might as well not do the work twice 3. A. Some good answers: - constructor should populate fields, not populateTable() - probably want to populate fields from an input file, so don't make table const - destructor shouldn't delete table - populateTable doesn't need to return an ETable * - don't use magic numbers for table - use maps for table instead of a 2-D array - don't use bool, since you may want more nuances than just "isEffective/isNotEffective" - enum type should be public, not private B. Charisaur inherits the implementation of getWeaknesses from both flying and fire, so when we call getWeaknesses on a Charisaur instance, it is unclear which function we should call. C. Have individual Pokomon inherit directly from the Pokomon class (e.g., class Snarlox : public Pokomon). Add a private data field in the Pokomon class for the Pokomon's type. D. - make the functions in the base class pure virtual - store attacks as a map from a string (the attack's name) to an attack_t struct - Snarlox's stuff shouldn't be static - Charisaur's breatheFire method is unnecessary, as it is an attack that should be performed by the attack function - the second argument to attack shouldn't be const, as we'll probably want to alter the opponent's health in this function 4. A. template class MyStack { public: int size(); T pop(); void push(T obj); private: vector stack; int count; } B. would want to throw an exception from pop() if there was nothing in the stack C. MyStack s; try { s.pop(); assert(false); // will break if we don't throw an exception... } catch(...) { } // make sure size is initialized assert(s.size() == 0); // make sure push works s.push(5); s.push(10); // make sure count is updated assert(s.size() == 2); // make sure they come back in the correct order assert(s.pop() == 10); assert(s.pop() == 5); // make sure countn was updated again assert(s.size() == 0); 5. A. _ref_ctr should be a pointer to a shared refcount, not an instance. When the _ref_ctr gets copied, you do a deep copy of the int as it is, which is wrong, because then when you update the new int, you don't update the old int. Fix: Declare: RefCount *_ref_ctr; Make a "new RefCount()" in the constructor, and delete _ref_ctr in the destructor whenever we delete the p_data. B. SmartPointer& operator=(const SmartPointer &other) { if(&other == this) return *this; delete_helper(); ref_ctr = other.ref_ctr; p_data = other.p_data; return *this; } C. -Each pointer is twice as large (4 bytes for the pointer, 4 more bytes for the counter) -Very slight efficiency hit in terms of CPU, since you have to call through another function for each dereference. -Could be argued that you lose a bit of control over your pointer, since SmartPointer is going to automatically delete it.