Exam 2 Study Guide
You MUST present a picture ID
Exam Date: Monday/Tuesday April 21/22, 2003
Use the list of questions below as a guide when studying for Exam 2. It is by
no means a comprehensive list of all material that you are responsible for. In
general, you are responsible for the material presented in lecture since the first exam.
You are also responsible for all associated reading assignments.
I. Inheritance and Polymorphism
- Explain the differences among public, private, and protected member access specifiers.
Be sure to mention their role in inheritance.
- Explain how inheritance promotes code reuse
- Explain the difference between the "is a" and "uses a" relationships. Give an example
of each from the course projects.
- Explain how C++ implements "is a" relationship
- Explain how C++ implements "has a" relationship
- Describe the order in which constructors and destructors are called when using inheritance.
- Explain the use of the member initialization list for constructors.
- Explain the difference between function overriding function overloading.
- In terms of interface and implemenation, what is the purpose of a pure virtual
method in a base class?
- In terms of interface and implemenation, what is the purpose of a virtual
method in a base class?
- In terms of interface and implemenation, what is the purpose of a non-virtual
method in a base class?
- What is "ad hoc" polymorphism? Give an example.
- What is "parameteric" polymorphism? Give an example.
- What is "true" polymorphism? Give an example.
- Explain the difference between static (early) and dynamic(late) binding.
- Define abstract base class. Give an example from one of the course projects.
True/False
- A base class contains all data and methods which are common to all objects
in its inheritance hierarchy.
- In C++, public inheritance is used to support the "uses-a" relationship between objects.
- Aggregation (composition) is used to support the "has-a" relationship between objects.
- Like friends, a derived class has direct access to the base class' private data and methods.
- Dynamic binding is performed at run-time when the programmer uses pointers to functions.
- Because only virtual and pure virtual methods should be overridden,
all public methods in a base class should be declared as either virtual or pure virtual.
- The base class destructor is automatically called when a derived class object
is destroyed if the base class destructor is virtual.
- "True" polymorphism can only occur when using indirect access (pointers or references )
to objects.
- "True" polymorphism can only occur when using virtual or pure virtual methods.
- To invoke a virtual function for an object, your code must use a pointer
of the same type as the type of the object when it was originally declared.
- If a member function was declared as " virtual void foo() = 0;" then it is not necessary
to provide any definition of "foo" in the class.
- Polymorphism refers to how identical code can produce different effects
depending on the actual type of the object being processed.
- Polymorphism refers to how structure and behavior can be shared between similar kinds of
objects.
int main ( )
{
Lot ParkingLot;
Car chevy;
Car camry;
MotorCycle harley(3);
MotorCycle honda;
ParkingLot.park (chevy);
ParkingLot.park (honda);
ParkingLot.park (harley);
ParkingLot.park (camry);
ParkingLot.print( );
cout << endl;
cout << "The lot has: "
<< ParkingLot.totalWheels( )
<< " wheels" << endl;
return 0;
}
|
// Vehicle class
class Vehicle
{
public:
Vehicle ( int nrWheels = 0 );
virtual ~Vehicle ( void );
virtual void Print ( void ) const;
int GetWheels ( void ) const;
void SetWheels (int wheels );
private:
int m_nrWheels;
};
//------------------------------------
Vehicle::Vehicle (int wheels)
{
m_nrWheels = wheels;
}
//-------------------------------------
int Vehicle::GetWheels (void ) const
{
return m_nrWheels;
}
void Vehicle::SetWheels (int wheels)
{
m_nrWheels = wheels;
}
void Vehicle::Print ( void ) const
{
cout << "Vehicle";
}
Vehicle::~Vehicle ( void )
{
// no code
}
|
// Parking Lot class
const int maxVehicles = 20;
class Lot
{
public:
Lot ( void );
int NrParked ( void ) const;
void Park ( Vehicle& v );
int TotalWheels ( void ) const;
void Print( void ) const;
private:
int m_nrVehicles;
Vehicle *m_vehicles[maxVehicles];
};
//--------------------------------
Lot::Lot ( void )
{
m_nrVehicles = 0;
}
//----------------------------------
int Lot::NrParked (void) const
{
return m_nrVehicles;
}
//----------------------------------
void Lot::park (const Vehicle& vehicle)
{
m_vehicles[nrVehicles++] = &vehicle;
}
//----------------------------------
void Lot::print (void) const
{
for (int v = 0; v < nrParked(); v++)
{
(m_vehicles[v])->Print( );
cout << ":";
cout << (m_vehicles[v])->GetWheels();
cout << endl;
}
}
//---------------------------------
int Lot::TotalWheels ( void ) const
{
int w = 0;
for (int v = 0; v < NrParked(); v++)
w += (m_vehicles[v])->GetWheels();
return w;
}
|
// MotorCycle class
class MotorCycle : public Vehicle
{
public:
MotorCycle (int wheels = 2);
~MotorCycle ( void );
};
//---------------------------------
MotorCycle::MotorCycle (int wheels)
: Vehicle (wheels)
{
// no code
}
//===================
// Car class
class Car : public Vehicle
{
public:
Car (int wheels = 4);
void Print (void) const;
};
//------------------------------
Car::Car (int wheels)
: Vehicle (wheels)
{
// no code
}
void Car::Print (void) const
{
cout << "Car";
}
|
The following questions refer to the code above
- What two features of this code tell you that dynamic binding is taking place?
- What is the output from main() ?
- True/False -- The Vehicle class is an abstract class.
- True/False -- Motorcylce is derived from Vehicle.
- True/False -- Car is derived from Vehicle.
- True/False -- The Lot class is not intended to be a base class.
- True/False -- The compiler will prevent the Car class from overriding
Vehicle's GetWheels() method.
- True/False -- The compiler will not prevent the Car class from overriding
Vehicle's GetWheels() method, but it shouldn't do so.
- True/False -- SetWheels() cannot be used polymorphically because it's not a
virtual or pure virtual function.
II. Templates
- Consider this prototype for a template function:
template
void foo(Item x);
Which is the right way to call the foo function with an integer argument i?
- foo( i );
- foo<int>( i );
- foo<Item>( i );
- foo(<int> i );
- foo(<Item> i );
- Consider the following definition:
template
Item max (Item a, Item b)
{
if (a > b)
return a;
else
return b;
}
What restrictions are placed on the Item data type for a program that uses
the max function?
- The Item data type must be either int, double, or float.
- The Item data type must be one of the built-in C++ data types.
- The Item data type must have a copy constructor and a > operator defined.
- None of the above restrictions apply.
- When should a function be implemented as a template function?
- When the data types of the parameters all have copy constructors.
- When the function is independent of the underlying data type.
- When the function is relatively short (usually just one line).
- When the function only takes one argument.
- Briefly explain the advantage(s) of function templates.
- Write a template function named Largest( ) that returns the largest of a
vector of homogenous objects passed to it. The return value is the index into the vector
at which the largest object was found. If more than one object is "largest",
return the index of the first one found.
- Write a small code fragment (variable declarations and function call) that shows how
Largest( ) would be called from main( ) for a vector of objects of type BOB.
- What attribute(s) of a function makes it appropriate to be a function template?
- Although function/template classes are designed to be used for any
class, why might using a template with some classes cause a compiler
error? Give an example.
- Write a template class definition for a class named Box that contains
homogenous data and supports the following operations. The capicity of the
Box cannot change. What design decisions must be considered for these
Box operations?
- Create a new Box. The capacity of the box is 25 items by default unless
another capacity is specified by the user.
- Puts an item into the Box
- Removes an item from the Box
- Tells how many items are in the Box
- Empties the box
Given the class template for Box above
- Write a declaration for a Box that holds 10 integers
- Write a declaration for Box that holds 25 XYZ objects
- Write the code for operator<< for the Box class
- What syntax error, if any, is present in this implementation
for the Box destructor?
template
Box::~Box( )
{
// code here
}
- Given the following simple class:
class MyArray
{
public:
MyArray();
~MyArray();
int &operator[](int k);
private:
int m_theData[66];
};
Rewrite the definition (do not define the member function and constructors, just declare
them) as a template class which takes the type being stored as a template arguments.
- Implement the member function operator[] from the MyArray class above.
Throw an exception of your choosing if you detect a bad index.
III. (Linked) Lists
Unless otherwise noted, assume the Linked List is a singly linked list.
Use the following class definitions
template< class T>
class Node
{
Node( T data, Node *next = NULL);
T m_data;
Node *m_next;
friend class List< T>;
}
template < class T>
class List
{
public:
List ( void );
~List( void );
bool Insert( const T& item);
bool Remove( const T& item);
bool Find (const T& item) const;
private:
Node *m_head;
};
- List two advantages of using an array to implement a List.
- List two advantages of using a Linked List to implement a List.
- Explain the algorithm and special cases, if any, for inserting nodes into a linked list.
- Write the code for the List Insert() method that always inserts new items
at the beginning of the List.
- Explain the algorithm and special cases, if any, for removing a node from a linked list.
- Explain why the List ADT should be implemented as a class template.
- The constructor of the Linked List Node class is private and as a result,
the List class is made a friend of the Node. Is this a good idea? If so, why?
If not, why not?
- Write the prototype and implementation for the overloaded operator + which creates a
List which is the concatenation (appending of) of two Lists. The return value is the new
List. The original Lists are parameters which are not changed.
For example, if L1 = {2 7 43 3 1} and L2 = {5 1 56 33} then after the
statement L3 = L1 + L2; L3 = {2 7 43 3 1 5 1 56 33}.
- Write the prototype and implementation for a new member function named
Sum() that adds all of the data elements in a List and returns
the result by value.
- The code below from the List destructor is intended to delete all nodes from a linked list,
but isn't quite right. Identify the error, explain the problem(s) caused by
the error and rewrite the code to fix the error.
Node *nodep;
while (m_head != NULL)
{
nodep = m_head;
delete nodep;
m_head = m_head->next;
}
- Draw a diagram of a singly linked list of integers that contains
the values {2, 4, 6, 8} in that order.
- Draw a diagram of a singly linked circular list of integers that contains
the values {2, 4, 6, 8} in that order.
- Draw a diagram of a doubly linked list of integers that contains
the values {2, 4, 6, 8} in that order.
- Draw a diagram of a doubly linked circular list of integers that contains
the values {2, 4, 6, 8} in that order.
- Assume that the Node class above has been modified to support a doubly
linked list by the addition of Node *previous; as a private data
member. Write the implementation of Remove() for the doubly linked list.
IV. Exceptions
- Name one important advantage of using the C++ exception methodology.
- For the function template Largest() above, what condition(s), if any, might
cause an exception to be thrown?
- Briefly explain how exceptions are implemented in C++.
- Describe the process of "stack unwinding" which occurs if an exception is not caught.
- Rewrite the following function so that any exceptions which are thrown by the
functions set(), game(), and match() are caught within the function play().
Your code should print a message inidicating the type of exception caught
and then call exit() if any exception is thrown. Assume that match()
throws objects of type MatchEx and game()
throw objects of type GameEx, both of which are defined elsewhere. Assume that
set() throws an integer.
Score play( void )
{
Score s;
while (!match( ))
{
while (!game( ))
{
s = set( );
}
}
return s;
}
- Suppose you have implemented a class named MyVector which defines
and implments the function operator[] ( ) that performs the ususal
indexing. Your initial implementation (below) of operator[] ( ) uses
assert() to indicate that the index is out of bounds. Change the
code for operator[] ( ) to throw an exception in this situation.
Define an exception class to be used as the type of the exception thrown
template< class T>
T MyVector::opertor[] ( int i ) const
{
assert ( i >= 0);
assert ( i < MyVector.size() );
return m_theData[ i ];
}
True/False
- Exception classes are different from other classes because they can only contain error messages.
- Only one try block is allowed in a program.
- A try block can have multiple catch blocks.
- Exceptions that are not caught by your program result in a run-time error and core dump.