Curriculum
Course: Learn C++
Login

Curriculum

Learn C++

Text lesson

Understanding Class Template and Function Template in C++

In this lesson, you will learn

  • Class Templates
  • Need of Class Templates
  • Function Template
  • Examples

 

Class Templates

  • Class templates in C++ are a powerful feature that allows you to create generic classes.
  • You can define a class without specifying the exact data type it will use, making it reusable for different types without rewriting the code for each type.
  • Class templates make code more flexible and reduce redundancy.

Generic classes are useful when a class uses logic that can be generalized. For Example, The same algorithms which is maintaining a queue of integers will also work for a queue of characters.

 

 

Why Use Class Templates?

  1. Code Reusability: Write a single class definition that can work with any data type.
  2. Type Safety: Templates are checked at compile time, avoiding type-related errors.
  3. Efficiency: Templates allow code to be optimized for specific types during compilation.

Class templates are generally used for data storage (container) classes. The major examples, you will see in the next chapter i.e. Standard Template Library (STL).

 

Need for the Class Templates

Let us create a Stack class that stores data only of type int.

class Stack
{
private:
    int st[MAX]; //array of ints
    int top; //index number of top of stack
public:
    Stack(); //constructor
    void push(int var); //takes int as argument
    int pop(); //returns int value
};

If we wanted to store data of type long in a stack, we would need to define a completely separate class such as

class LongStack
{
private:
    long st[MAX]; //array of longs
    int top; //index number of top of stack
public:
    LongStack(); //constructor
    void push(long var); //takes long as argument
    long pop(); //returns long value
};

Similarly, you need to create a new stack class for every data type we want to store.

It would be nice if you would be able to write a single class specification that would work for variables of all types, instead of a single basic type.

As you may have guessed, class templates allow us to do this. So, let’s learn the class templates.

 

Basic Syntax of a Class Template

Here’s a general structure:

template<typename T>
class ClassName {
   T member;  // 'T' can be any data type
   public:
      ClassName(T arg) : member(arg) {}  // Constructor accepting type T
      T getMember() { return member; }   // Method using type T
};

Breaking Down the Syntax:

  1. template <typename T>

    • The template keyword tells the compiler that the following class is a template.
    • typename T (or alternatively class T) declares T as a placeholder for a type. You can use any name instead of T, but T is conventional.
    • This means T can be any type (like int, double, string, or even another class).
  2. class ClassName

    • Defines the class, just like a regular class, but it uses T as a placeholder for any data type.
  3. T

    • Inside the class definition, T is used wherever you would normally specify a data type. This makes the class generic.

Once you have created a generic class, you create a specific instance of that class using the following general form:

class-name<T> ob;

Here, T is the type name of the data that the class will be operating upon.

Note: Member functions of a generic class are themselves automatically generic. You need not use the template to explicitly specify them as such.

 

More Advanced Syntax: Multiple Template Parameters

You can have multiple types as parameters if needed:

template<typename T, typename U>
class ClassName {
   // Class definition using 'T' and 'U' as placeholders for data types
};

In this case, T and U are different placeholders that allow the class to handle more than one type.

 

Example 1: Using A Simple Template Class

Here’s a simple example using a class template for storing a single item of any data type:

#include<iostream>
using namespace std;

template<typename T>
class Box {
    T content;
public:
    Box(T c) : content(c) {}
    T getContent() { return content; }
};

int main() {
    Box intBox(123);         // Box for integers
    Box doubleBox(45.67); // Box for doubles
    Box stringBox("Hello"); // Box for strings

    cout << "Int Box: " << intBox.getContent() << endl;
    cout << "Double Box: " << doubleBox.getContent() << endl;
    cout << "String Box: " << stringBox.getContent() << endl;

    return 0;
}

 

Example 2: A Template Class with Multiple Parameters

You can also define templates with more than one type parameter:

#include<iostream>
using namespace std;

template<typename T, typename U>
class Pair {
    T first;
    U second;
public:
    Pair(T a, U b) : first(a), second(b) {}
    void display() {
        cout << "First: " << first << ", Second: " << second << endl;
    }
};

int main() {
    Pair<int, double> p1(10, 20.5);
    Pair<string, char> p2("Hello", 'A');

    p1.display();
    p2.display();

    return 0;
}

 

Function Template

Function templates enable you to write a generic function that can work with any data type.

 

Example-3: Using a Function Template

#include<iostream>
using namespace std;

// Function Template
template<typename T>
T getMax(T a, T b) {
    return (a > b) ? a : b;
}

int main() {
    int intMax = getMax(10, 20);        // Works with int
    double doubleMax = getMax(10.5, 7.8); // Works with double
    char charMax = getMax('a', 'z');    // Works with char

    cout << "Max of 10 and 20 is: " << intMax << endl;
    cout << "Max of 10.5 and 7.8 is: " << doubleMax << endl;
    cout << "Max of 'a' and 'z' is: " << charMax << endl;

    return 0;
}

Output:

Max of 10 and 20 is: 20
Max of 10.5 and 7.8 is: 10.5
Max of 'a' and 'z' is: z

Explanation:

  • The function getMax is a generic function that can operate on any data type (like int, double, char).
  • template <typename T> is the template definition, where T is a placeholder for any data type.
  • The compiler automatically determines the data type of T based on the function call.
  • In the example:
    • getMax(10, 20) treats T as int.
    • getMax(10.5, 7.8) treats T as double.
    • getMax('a', 'z') treats T as char.

 

More Practice Examples Using Templates

Example-1: A Template Class for a Simple Stack

A more complex example involves a stack that can work with any data type:

//ClassTemplatesEx1.cpp
#include<iostream>
using namespace std;
const int MAX = 100; //size of array

template <class Type>
class Stack
{
private:
    Type st[MAX]; //stack: array of any type
    int top; //number of top of stack
public:
    Stack() //constructor
    { top = -1; }
    
    void push(Type var) //put number on stack
    { st[++top] = var; }
    
    Type pop() //take number off stack
    { return st[top--]; }
};

int main()
{
    Stack<float> s1; //s1 is object of class Stack<float>
    s1.push(11.1F); //push 3 floats, pop 3 floats
    s1.push(22.2F);
    s1.push(33.3F);
    cout<<"1: "<<s1.pop()<<endl;
    cout<<"2: "<<s1.pop()<<endl;
    cout<<"3: "<<s1.pop()<<endl;
    
    Stack<long> s2; //s2 is object of class Stack<long>
    s2.push(123123123L); //push 3 longs, pop 3 longs
    s2.push(234234234L);
    s2.push(345345345L);
    cout<<"1: "<<s2.pop()<<endl;
    cout<<"2: "<<s2.pop()<<endl;
    cout<<"3: "<<s2.pop()<<endl;
    
    return 0;
}

Output

1: 33.3      
2: 22.2      
3: 11.1      
1: 345345345 
2: 234234234 
3: 123123123

 

Example-2: A Template Class for a Simple Stack

#include<iostream>
using namespace std;

template<typename T>
class Stack {
    T arr[10];  // Fixed-size stack for simplicity
    int top;
public:
    Stack() : top(-1) {}
    void push(T value) {
        if (top < 9) {
            arr[++top] = value;
        } else {
            cout << "Stack overflow!" << endl;
        }
    }
    T pop() {
        if (top >= 0) {
            return arr[top--];
        } else {
            cout << "Stack underflow!" << endl;
            return T();  // Return a default-constructed object
        }
    }
};

int main() {
    Stack<int> intStack;
    intStack.push(5);
    intStack.push(10);
    cout << "Popped from int stack: " << intStack.pop() << endl;

    Stack<string> stringStack;
    stringStack.push("Hello");
    stringStack.push("World");
    cout << "Popped from string stack: " << stringStack.pop() << endl;

    return 0;
}

Output:

Popped from int stack: 10
Popped from string stack: World

 

 


End of the lesson….enjoy learning

 

 

Student Ratings and Reviews

 

5.0
5.0 out of 5 stars (based on 2 reviews)
Excellent100%
Very good0%
Average0%
Poor0%
Terrible0%

 

 

December 2, 2024

Error in example 2: A Template Class for a Simple Stack–>Interger and string specific instance of template have not been created

December 2, 2024

best content

 

 

Submit a Review

 

 

Layer 1
Login Categories