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; } |