Selected C++ Example #18
// Example #18
// This example code shows the attempt to implement three
// different lists (meal lists, airplane lists, and dog lists)
// with one implementation of the list code. The general approach
// is to use C++ templates to capture the common structure
// that all LinkedLists share. The template is then used to
// generate the three different lists. The advantage of templates
// over weakened type checking via inheritance (Example #17) is
// that mistakes of flying dogs off runways cannot occur (due to
// the maintenance of strong type checking by templates). The
// disadvantage is that we pay for the class/method code for each
// new data type that wishes to have a list instantiation.
#include <iostream.h>
#include <new.h>
// The derived classes Dog, Meal, and Airplane are only
// skeleton classes, to simplify their implementation.
class Dog {
public:
void bark();
void bite();
void print(ostream& o = cout);
};
void
Dog::bark()
{
cout << ''Bow Wow\n'';
}
void
Dog::bite()
{
cout << ''Ouch!!!\n'';
}
void
Dog::print(ostream& o)
{
o << ''I am a dog!\n'';
}
classMeal {
public:
void eat();
void print(ostream& o = cout);
};
void
Meal::eat()
{
cout << ''Crunch ... Munch ... Crunch ...\n'';
}
void
Meal::print(ostream& o)
{
o << ''I'm a meal\n'';
}
class Airplane {
public:
void fly();
void print(ostream&o = cout);
};
void
Airplane::fly()
{
cout << ''Va-a-a--room!!!\n'';
}
void
Airplane::print(ostream& o)
{
o << ''I'm an airplane!\n'';
}
// Borland wouldn' t accept nested templates, so the Node class is
// placed outside the scope of the LinkedList.
template <class DATUM>
struct Node {
DATUM data;
Node* next;
public:
Node(DATUM&);
};
template <class DATUM>
class LinkedList{
Node<DATUM>* head;
int len;
public:
LinkedList();
~LinkedList();
int insert(DATUM&);
DATUM remove();
void traverse() const;
int length();
};
template <class DATUM>
Node<DATUM>::Node(DATUM& new_item)
{
data = new_item;
next = NULL;
}
template <class DATUM>
LinkedList<DATUM>::LinkedList()
{
head = NULL;
len = 0;
}
template <class DATUM>
LinkedList<DATUM>::~LinkedList()
{
Node<DATUM>* temp;
while (head != NULL) {
temp = head;
head = head->next;
delete temp;
}
}
template <class DATUM>
int
LinkedList<DATUM>::insert(DATUM& new_item)
{
Node<DATUM>* temp = head;
if (temp == NULL) {
head = new Node<DATUM>(new_item);
}
else {
while (temp->next != NULL) {
temp = temp->next;
}
temp->next = new Node<DATUM>(new_item);
}
return(++len);
}
template <class DATUM>
DATUM
LinkedList<DATUM>::remove()
{
Node<DATUM>* temp = head;
static DATUM bad_item;
DATUM retval;
if (temp == NULL) {
return(bad_item);
}
else {
retval = head->data;
head = head->next;
len--;
delete temp;
return(retval);
}
}
// Notice that the traverse method sends a message to the
// data in each node to print itself. This sets up a requirement
// that any data type that wants to be in a LinkedList needs
// a print method. An even more important consideration is
// the fact that the syntax is different if DATUM is a pointer
// or nonpointer. Nonpointers would use a dot, and not
// an arrow, operator. The template requires its DATUM to be
// a pointer (in this example), and that the DATUM possess a
// print method.
template <class DATUM>
void
LinkedList<DATUM>::traverse() const
{
Node<DATUM>* temp = head;
cout << ''(\n'';
while (temp != NULL) {
temp->data->print();
cout << ''\n'';
temp = temp->next;
}
cout << '')\n\n'';
}
template <class DATUM>
int
LinkedList<DATUM>::length()
{
return(len);
}
void
main()
{
LinkedList<Meal*> MealList;
LinkedList<Airplane*> AirplaneList;
LinkedList<Dog*> DogList;
// The following template expansion would generate errors due to
// the traverse method requiring a pointer data type (or at least
// a data type that supports the ''->'' operator).
//
// LinkedList<Dog> x;
//
Meal *meal1 = new Meal, *meal2 = new Meal, *meal3 = new Meal;
Dog *dog1 = new Dog, *dog2 = new Dog, *dog3 = new Dog;
Airplane *air1 = new Airplane, *air2 = new Airplane, *air3 =
new Airplane;
// At first glance everything seems to work nicely
MealList.insert(meall);
MealList.insert(meal2);
MealList.insert(meal3);
Meal* aMeal = (Meal*) MealList. remove();
aMeal->eat();
char c;
cin >> c;
AirplaneList.insert(air1);
AirplaneList.insert(air2);
AirplaneList.insert(air3);
DogList.insert(dog1);
DogList.insert(dog2);
DogList.insert(dog3);
MealList.traverse();
AirplaneList.traverse();
DogList.traverse();
cin >> c;
// The following line of code would generate compiler errors due to
// the preservation of strong type checking by the C++ template
// mechanism.
//
// AirplaneList.insert(dog2);
delete meal1;
delete meal2;
delete meal3;
delete dog1;
delete dog2;
delete dog3;
delete air1;
delete air2;
delete air3;
}
|