13.6.1. Stack Example

The following example uses a stack to demonstrate a general, template-based data structure. But it isn't the first example based on a stack. Previously, we've studied automatic and dynamic stack implementations. And most recently, we used a stack class to illustrate The "this" Pointer. For brevity, the current example focuses only on the automatic implementation, but it presents two versions.

  1. Sets a fixed stack size, wasting space if the size is much larger than needed, or failing if the size is too small.
  2. Allows the user to specify the stack size through a template variable. Specifying a default size, = 100, is optional.
Fixed SizeTemplate Variable Size
template <class T>
class stack
{
	private:
		static const int SIZE = 100;
		T	st[SIZE];
		int	sp;
template <class T, int SIZE = 100>
class stack
{
	private:
		T	st[SIZE];
		int	sp = 0;

(a)(b)
template <class T>
T stack<T>::pop()
template <class T, int SIZE>
T stack<T, SIZE>::pop()
(c)(d)
Fixed size stack vs. a variable sized stack. There is little difference between the two versions. There are some minor differences between the classes and the function headers, but the function bodies are the same. The differences are highlighted here.
  1. A partial stack class. The yellow-highlighted syntax makes stack a template class. The blue-highlighted statement creates a class-scope symbolic constant that fixes the stack size at 100 elements.
  2. Another partial stack class, but this version adds a template variable with a default value (in red). The template variable allows an application programmer to specify the stack size with a template argument. If we omit the default value, the application programmer must provide a stack size. Figure 3 illustrates how to accept or override the default stack size.
  3. The "boilerplate" syntax used to introduce each stack function when there is only a type template variable.
  4. The "boilerplate" syntax used to introduce each stack function when there are two template variables - one for the generalized class and another for the size of the stack.
#include <iostream>
using namespace std;

template <class T, int SIZE = 100>
class stack
{
	private:
		T	st[SIZE];
		int	sp = 0;

	public:
			stack();
		void	push(T data);
		T	pop();
		int	size();
		T	peek();
};

template <class T, int SIZE>
stack<T, SIZE>::stack() {}

template <class T, int SIZE>
void stack<T, SIZE>::push(T data)
{
	if (sp < SIZE)
		st[sp++] = data;
	else
		throw "Stack overflow";
}

template <class T, int SIZE>
T stack<T, SIZE>::pop()
{
	if (sp > 0)
		return st[--sp];
	else
		throw "Stack underflow";
}

template <class T, int SIZE>
int stack<T, SIZE>::size()
{
	return sp;
}

template <class T, int SIZE>
T stack<T, SIZE>::peek()
{
	if (sp >= 1)
		return st[sp - 1];
	else
		throw "Stack underflow";
}
stack.h. The stack class implemented as a template is a simple but library-quality data structure. The class has two aspects worth our attention:
#include  <iostream>
#include  "stack.h"
using  namespace  std;

int main()
{
	stack<int, 10>	s;
	stack<double>	d;

	s.push(10);
	s.push(20);
	d.push(2.7);
	d.push(3.1459);

	cout << s.pop() << endl;
	cout << s.pop() << endl;
	cout << d.pop() << endl;
	cout << d.pop() << endl;

	return 0;
}
driver.cpp. A driver program demonstrating how to specify the data that that replaces the template variable T. The first stack, s, overrides the default stack size with the second template argument (10). The second stack, d, accepts the default stack size of 100; this option is not available if we omit the default size.

Downloadable Code