Menu
Coddy logo textTech

Class Templates

Part of the Object Oriented Programming section of Coddy's C++ journey — lesson 65 of 104.

Just as function templates let you write type-independent functions, class templates let you create type-independent classes. This is how containers like std::vector work - you define the structure once, and the compiler generates specific versions for each type you use.

template <typename T>
class Box {
    T value;
public:
    Box(T v) : value(v) {}
    T getValue() const { return value; }
    void setValue(T v) { value = v; }
};

int main() {
    Box<int> intBox(42);
    Box<std::string> strBox("Hello");
    
    std::cout << intBox.getValue() << std::endl;  // 42
    std::cout << strBox.getValue() << std::endl;  // Hello
}

Unlike function templates, you must explicitly specify the type when creating objects from class templates using angle brackets. The compiler then generates a complete class definition for that specific type.

Class templates can have multiple type parameters and even non-type parameters like integers:

template <typename T, int Size>
class FixedArray {
    T data[Size];
public:
    T& operator[](int index) { return data[index]; }
    int size() const { return Size; }
};

FixedArray<double, 5> arr;  // Array of 5 doubles
arr[0] = 3.14;

When defining member functions outside the class, you must repeat the template declaration:

template <typename T>
class Container {
    T* data;
public:
    Container();
    ~Container();
};

template <typename T>
Container<T>::Container() : data(nullptr) {}

template <typename T>
Container<T>::~Container() { delete data; }

Class templates form the foundation of generic programming in C++, enabling you to write reusable data structures that work with any type.

challenge icon

Challenge

Easy

Let's build a generic storage system using class templates to create a flexible container that can hold any type of data. You'll organize your template class in a header file and demonstrate its versatility with different types in your main program.

You'll create two files:

  • Storage.h: Define a class template called Storage that acts as a simple container for a single value with some useful operations:

    Your Storage template should have:

    • A private member to hold the stored value
    • A constructor that takes an initial value
    • A getValue() method that returns the stored value
    • A setValue() method that updates the stored value
    • An isEmpty() method that returns true if the value equals the default-constructed value of type T, false otherwise

    Also create a class template called Pair with two type parameters that stores two related values:

    • Private members for the first and second values (of potentially different types)
    • A constructor that initializes both values
    • Methods getFirst() and getSecond() to retrieve each value
    • A display() method that prints: (<first>, <second>)
  • main.cpp: Read four inputs (each on a separate line):
    1. An integer value
    2. A new integer value
    3. A string value
    4. A double value

    Demonstrate your templates by:

    1. Creating a Storage<int> with the first integer, printing: Int storage: <value>
    2. Updating it with the second integer using setValue(), then printing: Updated: <value>
    3. Creating a Storage<std::string> with the string input, printing: String storage: <value>
    4. Checking if the string storage is empty and printing: Is empty: <true/false> (print true or false)
    5. Creating a Pair<std::string, double> with the string and double values, then calling display()
    6. Creating a Pair<int, int> with both integer inputs, then calling display()

For example, with inputs 42, 100, Hello, and 3.14:

Int storage: 42
Updated: 100
String storage: Hello
Is empty: false
(Hello, 3.14)
(42, 100)

Notice how the same Storage template works seamlessly with integers and strings, and how Pair can combine different types together. The compiler generates separate class definitions for each type combination you use. Remember to use the template <typename T> syntax for single-type templates and template <typename T, typename U> for templates with multiple type parameters.

Cheat sheet

Class templates allow you to create type-independent classes. The compiler generates specific versions for each type you use.

Basic Class Template

template <typename T>
class Box {
    T value;
public:
    Box(T v) : value(v) {}
    T getValue() const { return value; }
    void setValue(T v) { value = v; }
};

When creating objects from class templates, you must explicitly specify the type using angle brackets:

Box<int> intBox(42);
Box<std::string> strBox("Hello");

Multiple Type Parameters

Class templates can have multiple type parameters:

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

Non-Type Parameters

Templates can also accept non-type parameters like integers:

template <typename T, int Size>
class FixedArray {
    T data[Size];
public:
    int size() const { return Size; }
};

FixedArray<double, 5> arr;  // Array of 5 doubles

Defining Member Functions Outside the Class

When defining member functions outside the class, repeat the template declaration:

template <typename T>
class Container {
    T* data;
public:
    Container();
    ~Container();
};

template <typename T>
Container<T>::Container() : data(nullptr) {}

template <typename T>
Container<T>::~Container() { delete data; }

Try it yourself

#include <iostream>
#include <string>
#include "Storage.h"

using namespace std;

int main() {
    // Read inputs
    int intValue1;
    int intValue2;
    string strValue;
    double doubleValue;
    
    cin >> intValue1;
    cin >> intValue2;
    cin >> strValue;
    cin >> doubleValue;
    
    // TODO: Create Storage<int> with first integer and print: Int storage: <value>
    
    // TODO: Update with second integer using setValue(), print: Updated: <value>
    
    // TODO: Create Storage<std::string> with string input, print: String storage: <value>
    
    // TODO: Check if string storage is empty, print: Is empty: true/false
    
    // TODO: Create Pair<std::string, double> with string and double, call display()
    
    // TODO: Create Pair<int, int> with both integers, call display()
    
    return 0;
}
quiz iconTest yourself

This lesson includes a short quiz. Start the lesson to answer it and track your progress.

All lessons in Object Oriented Programming