Name: __________________________________ CS Login Name: ________ | Section :________ |
Question | Topic | Possible | Score |
---|---|---|---|
1 | Review Terms and Concepts | 35 | |
2 | Pointers | 18 | |
3 | Dynamic Allocation | 10 | |
4 | Dynamic ADTs | 17 | |
5 | Instructor | 20 | |
Total | 100 |
The copy constructor ...
i. is automatically called when an object is passed
by value
ii. does a memberwise copy by default
iii. must be defined if your class uses public data members
iv. is automatically called when an array is dynamically allocated
Overloading allows ...
i. operators to be given new meaning
ii. two or more classes to use the same name
iii. operator precedence to be changed
iv.two or more functions to use the same function name
the const modifier ...
i. is used to keep reference parameters from changing
ii. cannot be placed after a type name
iii. is used to insure a method doesn't change its object's
data
iv. cannot be used with pointers
ii. The private section is part of the class implementation.
iii. A friend function can access a class's private members but is not a member of that class.
iv. A block is a list of statements nested within curly braces, and also marks
the boundaries of the local scope.
OOP has a few distinct advantages over non-OOP languages:
Objects can have unique behavior covered with a common interface. The implementation details of the object can be both hidden and protected from the user of the object. That implmentation can be modified, while the interface remains constant.
Class can inherit properties from parent class, thus reducing the need to reduntantly repeat code common to both classes. Inheritance also facilitates class enhancements without the need to rewrite a lot of code.
e.) [3 pts] What is compiling and why do we need to do it?
Compiling is the process of translating a high-level abstract language which a human easily understands, into a low-level concrete language easily processed by the computer. A prime example is compiling C++ code into executable machine language, as we do with the Visual C++ compiler.
f.) [3 pts] Name and describe two main types of errors encountered when programming.
Compiler Errors:
Programming Errors:
.----. a | o-|-----. `----' | .----. | b | 22 | <---+ `----' | .----. | c | o-|-----' `----'
ii. char a[] = "winter";
int *b = a[3];
Correction: char *b = &a[3];
*b = 'n';
*a = 'd';
.-----+-----+-----+-----+-----+-----+------. a | 'd' | 'i' | 'n' | 'n' | 'e' | 'r' | '\0' | `-----+-----+-----+-----+-----+-----+------' ^ .---. | b | o-|----------------' `---'
iii. struct Nibble { int a, b, c, d; };
Nibble n;
Nibble *ptr = &n;
n.a = n.b = n.c = 11;
ptr->a = 22;
.----------------------------------------. | .----. .----. .----. .----. | n | a | 22 | b | 11 | c | 11 | d | ? | | .---->| `----' `----' `----' `----' | | `----------------------------------------' | .---. ptr | o | `---'
b.) [6 total - 3 pts each] Explain what is wrong with each of the following uses of dynamic memory.
ii. char *word = new char[22];
delete word;
delete word; would only delete the first object element in the array. We must remind the compiler that word points to an array of characters by using: delete [] word;.
If a copy constructor is not defined by the programmer, then the compiler supplies a default copy contructor, which does a memberwise copy of the object. This is also known as a shallow copy, because when pointers are encountered, only the pointer's value is copied, not the structure pointed at. So if the original object's pointer points to an array, the copied object's pointer will point to that same array. This will cause problems when when object's array is modified, both objects will see the modification. Worse yet, if one object is deleted, allow with its allocated memory, then the other object's array will suddenly disappear, leaving dangling pointers.
#include <iostream.h> class Vector { public: Vector (int max); Vector (const Vector & other); ~Vector(); void Print (ostream & out) const; private: int _max; int _last; int * _list; }; // Auxilary Functions ostream & operator << (ostream & out, const Vector & v);
}; a.) [4 pts] Define the constructor for the Vector class having a default size of 512 when a size isn't specified. The vector begins with an empty list. Also fill in the prototype and data members above.
Vector::Vector (int max = 512) { _max = max; _last = 0; _list = new int [max]; }
b.) [3 pts] Define the destructor for the Vector class. Also fill in the prototype above.
Vector::~Vector () { if (_list != NULL) delete [] _list; }
Vector::Vector (const Vector & other) { _max = other._max; _last = other._last; _list = new int [_max]; for (int i = 0 ; i < _max ; i++) { _list[i] = other._list[i]; } }
d.) [5 pts] Define the << operator for the Vector class. Also fill in the prototype above. This method can be used to output the vector of integers, one per line, to either the screen or a file. Your implementation should also allow chaining (e.g. cout << "vector: " << v << endl; where v is a Vector object).
void Vector::Print (ostream & out) const { for (int i = 0 ; i <= _last ; i++) { if (i > 0) out << ','; out << _list[i] << endl; } } ostream & operator << (ostream & out, const Vector & v) { v.Print (out); return out; }
a.) [5 pts] Given below are two pieces of code, one which represents an is-a relationship, and the other which represents a has-a relationship. First, label each piece of code with the type of relationship it represents. Second, briefly explain why relationships are the way you chose them.
class Golly { public: Golly () ; Golly (int size); Golly (const Golly & g); void Add (Wolly w); private: Wolly * _wollies; } class Wolly { public: Wolly (); Wolly (const Wolly & w) private: int _nonsense; } |
class Wolly { public: Wolly (); Wolly (const Wolly & w) private: int _nonsense; } class Golly : public Wolly { public: Golly () ; Golly (int size); Golly (const Golly & g); private: int _moreInfo; } |
Relationship: has-a | Relationship: is-a |
Why: Class Golly contains (has-a) variable of type Wolly. | Why: Class Golly is a subclass of Wolly. A Golly is-a Wolly. |
a.) [15 pts] Write a complete program, which given its arguments (not including argv[0]), reverses the order of the arguments, and also reverses the characters of each argument itself. The program then prints the new arguments to the screen.
For example, if the program is called reverse, then typing reverse hello to all intelligent life would produce the following output: efil tnegilletni lla ot olleh.
#include <iostream.h> void swap (char & a, char & b) { char tmp = a; a = b; b = tmp; } void swap (char * & a, char * & b) { char *tmp = a; a = b; b = tmp; } void reverse (char * str) { int len = strlen (str); for (int i = 0 ; i < len / 2 ; i++) { swap (str[i], str[len-i-1]); } } int strlen (char *s) { int len; for (len = 0 ; *s != '\0' ; s++); return len; } void main (int argc, char * argv[]) { // First, reverse the order of arguments for (int i = 1 ; i < argc / 2 ; i++) { swap (argv[i], argv [argc-i]); } // Now reverse the characters in each argument // and then print the argument for (int i = 1 ; i < argc ; i++) { reverse (argv[i]); if (i > 1) cout << ' '; cout << argv[i]; } cout << endl; }