C++ Class Templates


C++ Class Templates: A Complete Guide

In C++, a class template is a blueprint for creating classes that can operate with any data type. With class templates, you can create generic classes that work with multiple data types, reducing code duplication and improving reusability. This article will explain how class templates work, their benefits, and provide practical examples to illustrate their use.


What is a C++ Class Template?

A class template allows you to define a class with placeholder data types. Instead of specifying a fixed type, class templates enable you to define a class that works with any type. The specific data type is defined when you create an instance of the class.

Syntax of a Class Template:

template <typename T>
class ClassName {
    T member_variable;
public:
    ClassName(T value);
    void display();
};
  • template <typename T>: This defines a template with a placeholder type T.
  • T member_variable: This is a member variable of type T.
  • ClassName(T value): This constructor takes a parameter of type T.
  • void display(): A function that works with the T type.

The T can be replaced with any data type (like int, double, etc.) when the class is instantiated.


Benefits of Using C++ Class Templates

  • Code Reusability: Create a class that can work with any data type without rewriting it for each type.
  • Type Safety: Templates are checked by the compiler, ensuring that the correct type is used.
  • Flexibility: Class templates can be used for many types, making them ideal for data structures like linked lists, stacks, or queues.

Sample Code: C++ Class Template

Example 1: A Simple Class Template for a Pair of Values

Let's create a basic class template that holds a pair of values and prints them.

#include <iostream>
using namespace std;

// Class template to store a pair of values
template <typename T>
class Pair {
private:
    T first;
    T second;
public:
    Pair(T f, T s) : first(f), second(s) {}
    
    void display() {
        cout << "First: " << first << ", Second: " << second << endl;
    }
};

int main() {
    Pair<int> intPair(10, 20);   // Pair of integers
    Pair<double> doublePair(3.14, 2.71);  // Pair of doubles
    
    intPair.display();   // Display integer pair
    doublePair.display();   // Display double pair
    
    return 0;
}

Explanation:

  • The Pair class is a template that holds two values of the same type, T.
  • We instantiate two objects: intPair (for integers) and doublePair (for doubles), each calling the display function to print the values.

Output:

First: 10, Second: 20
First: 3.14, Second: 2.71

Example 2: A Template Class for a Stack

Let's create a more complex example of a generic Stack class template that can store elements of any data type.

#include <iostream>
using namespace std;

// Class template for Stack
template <typename T>
class Stack {
private:
    T* arr;
    int top;
    int capacity;

public:
    Stack(int size) {
        arr = new T[size];
        capacity = size;
        top = -1;
    }

    void push(T value) {
        if (top == capacity - 1) {
            cout << "Stack Overflow!" << endl;
        } else {
            arr[++top] = value;
            cout << value << " pushed into stack" << endl;
        }
    }

    T pop() {
        if (top == -1) {
            cout << "Stack Underflow!" << endl;
            return T();  // Return default value for T
        } else {
            T poppedValue = arr[top--];
            return poppedValue;
        }
    }

    bool isEmpty() {
        return top == -1;
    }

    T peek() {
        if (top == -1) {
            cout << "Stack is empty!" << endl;
            return T();  // Return default value for T
        } else {
            return arr[top];
        }
    }
};

int main() {
    Stack<int> intStack(5);  // Stack of integers
    Stack<string> stringStack(3);  // Stack of strings

    intStack.push(10);
    intStack.push(20);
    cout << "Popped from int stack: " << intStack.pop() << endl;
    
    stringStack.push("Hello");
    stringStack.push("World");
    cout << "Popped from string stack: " << stringStack.pop() << endl;
    
    return 0;
}

Explanation:

  • The Stack class is a generic class that works with any data type T.
  • We can create a stack for integers (intStack) or strings (stringStack).
  • The push, pop, peek, and isEmpty functions are used to interact with the stack.

Output:

10 pushed into stack
20 pushed into stack
Popped from int stack: 20
Hello pushed into stack
World pushed into stack
Popped from string stack: World

Example 3: Class Template with Multiple Types

In some cases, you may want a class to accept multiple types. Here's how you can define a class template that works with two different data types.

#include <iostream>
using namespace std;

// Class template with two types
template <typename T, typename U>
class Pair {
private:
    T first;
    U second;
public:
    Pair(T f, U s) : first(f), second(s) {}

    void display() {
        cout << "First: " << first << ", Second: " << second << endl;
    }
};

int main() {
    Pair<int, double> pair1(5, 3.14);  // Pair of int and double
    Pair<string, char> pair2("Hello", 'H');  // Pair of string and char
    
    pair1.display();
    pair2.display();
    
    return 0;
}

Explanation:

  • The Pair class template now accepts two types, T and U.
  • We create two pairs: one of type int and double, and another of type string and char.

Output:

First: 5, Second: 3.14
First: Hello, Second: H

Template Specialization for Classes

Sometimes you might want to specialize a class template for a specific type. This can be done through template specialization.

Example: Specializing the Pair Class for char Type

#include <iostream>
using namespace std;

// General template
template <typename T>
class Pair {
private:
    T first;
    T second;
public:
    Pair(T f, T s) : first(f), second(s) {}

    void display() {
        cout << "First: " << first << ", Second: " << second << endl;
    }
};

// Specialization for char type
template <>
class Pair<char> {
private:
    char first;
    char second;
public:
    Pair(char f, char s) : first(f), second(s) {}

    void display() {
        cout << "Specialized Pair for char: " << first << ", " << second << endl;
    }
};

int main() {
    Pair<int> intPair(1, 2);
    Pair<char> charPair('A', 'B');

    intPair.display();
    charPair.display();

    return 0;
}

Explanation:

  • We define a specialized version of the Pair class template for char types.
  • The general Pair class works for all types except char, which uses the specialized version.

Output:

First: 1, Second: 2
Specialized Pair for char: A, B