------------------------------------------------------------------------------
MC logo
Generalized Stack Class
[^] Code Examples
------------------------------------------------------------------------------
<<PrintMe Test Driver genstack.h Generalized Stack Implementation>>
#include <iostream>

using namespace std;

//
//*****************************************************************************
//* Simple C++ stack package using a generalized base class for the stack
//* items.
//*****************************************************************************
//

// Stack items must be derived from this class.  Since C++ has nothing
// like Java's Object, we cannot just create a stack of those.
class Stack_Elt
{
 public:
        // All we know is that we can print it.  This is an abstract
        // function, called "pure virtual" in C++ terminology.
        virtual void print(ostream&) const = 0;
};

// Here is the class itself.
class Stack
{
 private:
        // Nodes.
        struct Node
        {
         public:
                Stack_Elt *data;
                Node *next;
                Node(Stack_Elt *e, Node *n = 0) {
                        data = e;
                        next = n;
                };
        };

        // Head of the list.
        Node *head;
 public:
        // Create an empty stack.
        Stack() { head = 0; }

        // Destroy the stack.  The data itself (pointed to by each stack
        // node) is not deleted.
        ~Stack() {
                while(!empty()) { pop(); }
        }

        // Add an element to the stack.  Note that you must send a pointer,
        // and the stack actually stores the pointer.
        void push(Stack_Elt *e)
        {
                head = new Node(e, head);
        }

        // Pop the stack and return the top item pointer.  If the stack is
        // empty, return the null pointer.
        Stack_Elt *pop();

        // Return the top item pointer.  If none, return the null pointer.
        Stack_Elt *top() {
                if(head == 0) return 0;
                return head->data;
        }

        // Tell if the stack is empty.
        bool empty() const { return head == 0; }

        // Print the stack.
        void print(ostream &strm) const;
};
inline ostream & operator<<(ostream &strm, const Stack &s)
{
        s.print(strm);
        return strm;
}

// Here is a second version of stack which deletes each data item when it
// is destroyed.  It also adds a method pop_n_trash() which removes the top
// element and also deletes it.
class SelfCleaningStack: public Stack
{
 public:
        ~SelfCleaningStack() {
                while(!empty()) { pop_n_trash(); }
        }

        void pop_n_trash() {
                Stack_Elt *zombie = pop();
                delete zombie;
        }
};

C++ does not have a universal base like like Java's class Object. When you create a generic data structure class, the usual approach is to define a class to serve as the base for the elements of the structure, Stack_Elt here. The element base class usually doesn't contain much, and may be entirely empty. If it contains anything, it is usually some pure abstract functions to define requirements which the user of the data structure must provide in the element class. In other words, it will tend to look a lot like a Java Interface, which is something else C++ doesn't have.

The = 0 on

virtual void print(ostream&) const = 0;

declares that the function is pure virtual, the same thing as an abstract function in Java. If this notation makes sense to you, congratulations.

Since polymorphism in C++ only works properly for pointers or references, we must build our stack as a stack of pointers to Stack_Elt. This means that the elements will usually be created with new, so will have to be deleteed. This raises the question: Should the stack destructor delete each content element, along with the node? The accepted answer is "No." The general practice is that a class should delete what it creates itself, and nothing else. The Stack class cannot create its own Stack_Elt objects, since it does not know what type they will be. Therefore, it should not attempt to delete them, either.

Some more reasons for stack not to delete its own elements:

In any of these cases, deleteing the pointer would be bad. Despite all this, I did provide an alternate version, SelfCleaningStack, which whos destructor deletes all contents. The user can simply use this one if wanted. Even so, the user will have to delete pointers returned by pop. If pop went ahead and did it, they would be quite useless after return.
<<PrintMe Test Driver Generalized Stack Implementation>>