Class Templates in C++

You can define generic types for a class.

In the preceding sections, you defined template functions with type parameters for the func­tion. You also can define template classes with type parameters for the class. The type param­eters can be used everywhere in the class where a regular type appears.

Recall that the StackOfIntegers class, defined in Section 10.9, “Case Study: The StackOfInteger Class,” can be used to create a stack for int values. Here is a copy of the class with its UML class diagram, as shown in Figure 12.1a.

1 #ifndef STACK_H
2
#define STACK_H
3
4
class StackOfIntegers
5 {
6   
public:
7    StackOfIntegers();
8   
bool empty() const;
9   
int peek() const;
10   
void push(int value);
11   
int pop();
12   
int getSize() const;
13
14   
private:
15   
int elements[100];
16   
int size;
17 };
18
19 StackOfIntegers::StackOfIntegers()
20 {
21   size =
0;
22 }
23
24
bool StackOfIntegers::empty() const
25 {
26   
return size == 0;
27 }
28
29
int StackOfIntegers::peek() const
30 {
31   
return elements[size – 1];
32 }
33
34
void StackOfIntegers::push(int value)
35 {
36   elements[size++] = value;
37 }
38
39
int StackOfIntegers::pop()
40 {
41   
return elements[–size];
42 }

43
44
int StackOfIntegers::getSize() const
45 {
46   
return size;
47 }
48
49
#endif

By replacing the highlighted int in the preceding code with double, char, or string, you easily can modify this class to define classes such as StackOfDouble, StackOfChar, and StackOfString for representing a stack of double, char, and string values. But, instead of writing almost identical code for these classes, you can define just one template class that works for the element of any type. Figure 12.1b shows the UML class diagram for the new generic Stack class. Listing 12.4 defines a generic stack class for storing elements of a generic type.

Listing 12.4 GenericStack.h

1 #ifndef STACK_H
2
#define STACK_H
3
4
template<typename T>
5
class Stack
6 {
public:
8    Stack();
9   
bool empty() const;
10   T peek()
const;
11   
void push(T value);
12   T pop();
13   
int getSize() const;
14
15
private:
16   T elements[
100];
17   
int size;
18 };
19
20
template<typename T>
21 Stack<T>::Stack()
22 {
23    size =
0;
24 }
25
26
template<typename T>
27
bool Stack<T>::empty() const
28 {
29   
return size == 0;
30 }
31
32
template<typename T>
33 T Stack<T>::peek()
const
34 {
35   
return elements[size – 1];
36 }
37
38
template<typename T>
39
void Stack<T>::push(T value)
40 {
41    elements[size++] = value;
42 }

43
44
template<typename T>
45 T Stack<T>::pop()
46 {
47   
return elements[–size];
48 }
49
50
template<typename T>
51
int Stack<T>::getSize() const
52 {
53   
return size;
54 }
55
56
#endif

The syntax for class templates is basically the same as that for function templates. You place the template prefix before the class definition (line 4), just as you place the template prefix before the function template.

template<typename T>

The type parameter can be used in the class just like any regular data type. Here, the type T is used to define functions peek() (line 10), push(T value) (line 11), and pop() (line 12). T also is used in line 16 to declare array elements.

The constructors and functions are defined the same way as in regular classes, except that the constructors and functions themselves are templates. So, you have to place the template prefix before the constructor and function header in the implementation. For example,

template<typename T>

Stack<T>::Stack()

{

size = 0;

}

template<typename T> bool Stack<T>::empty()

{

return size == 0;

}

template<typename T>

T Stack<T>::peek()

{

return elements[size – 1];

}

Note also that the class name before the scope resolution operator :: is Stack<T>, not Stack.

Listing 12.5 gives a test program that creates a stack for int values in line 9 and a stack for strings in line 18.

Listing 12.5 TestGenericStack.cpp

1 #include <iostream>
2
#include <string>

3 #include “GenericStack.h”
4 using namespace std;
5
6
int main()
7 {
8
// Create a stack of int values
9 Stack<int> intStack;
10
for (int i = 0; i < 10; i++)
11 intStack.push(i);
12
13
while (!intStack.empty())
14 cout << intStack.pop() <<
” “;
15 cout << endl;
16
17
// Create a stack of strings
18 Stack<string> stringStack;
19 stringStack.push(
“Chicago”);
20 stringStack.push(
“Denver”);
21 stringStack.push(
“London”);
22
23
while (!stringStack.empty())
24 cout << stringStack.pop() <<
” “;
25 cout << endl;
26
27
return 0;
28 }

To declare an object from a template class, you have to specify a concrete type for the type parameter T. For example,

Stack<int> intStack;

This declaration replaces the type parameter T with int. So, intStack is a stack for int values. The object intStack is just like any other object. The program invokes the push function on intStack to add ten int values to the stack (line 11), and displays the elements from the stack (lines 13-14).

The program declares a stack object for storing strings in line 18, adds three strings in the stack (lines 19-21), and displays the strings from the stack (line 24).

Note the code in lines 9-11:

while (!intStack.empty())

cout << intStack.pop() << ” “;

cout << endl;

and in lines 23-25:

while (!stringStack.empty())

cout << stringStack.pop() << ” “;

cout << endl;

These two fragments are almost identical. The difference is that the former operates on intStack and the latter on stringStack. You can define a function with a stack parameter to display the elements in the stack. The new program is shown in Listing 12.6.

Listing 12.6 TestGenericStackWithTemplateFunction.cpp

1 #include <iostream>
2
#include <string>
3
#include “GenericStack.h”
4 using namespace std;
5
6
template<typename T>
7
void printStack(Stack<T>& stack)
8 {
9   
while (!stack.empty())
10   cout << stack.pop() <<
” “;
11   cout << endl;
12 }
13
14
int main()
15 {
16   
// Create a stack of int values
17    Stack<int> intStack;
18   
for (int i = 0; i < 10; i++)
19    intStack.push(i);
20    printStack(intStack);
21
22   
// Create a stack of strings
23    Stack<string> stringStack;
24    stringStack.push(
“Chicago”);
25    stringStack.push(
“Denver”);
26    stringStack.push(
“London”);
27    printStack(stringStack);
28
29   
return 0;
30 }

The generic class name Stack<T> is used as a parameter type in a template function (line 7)

Source: Liang Y. Daniel (2013), Introduction to programming with C++, Pearson; 3rd edition.

Leave a Reply

Your email address will not be published. Required fields are marked *