Class templates are used to create classes that can operate with any data type. This allows a single class to handle multiple types of data without having to define separate classes for each type. A class template is a blueprint for generating class definitions based on the type or types provided at compile time.
Like function templates, class templates provide a mechanism to write generic, reusable, and type-safe code. They are particularly useful when working with data structures, like linked lists, stacks, queues, or other container-like classes, that need to store different types of data.
The basic syntax for defining a class template involves using the template keyword followed by a list of template parameters inside angle brackets (< >), and then defining the class using the template parameter(s).
template <typename T>
class ClassName {
private:
T value; // Data member of type T
public:
ClassName(T val) : value(val) {} // Constructor
T getValue() const { return value; } // Getter function
};
Here:
template <typename T> declares a template parameter T, which can be substituted with any type when the class is instantiated.value of type T, and the constructor initializes it with a value of type T.Let's define a simple Box class template that can store any type of object:
#include <iostream>
using namespace std;
// Class template to store a value of any type
template <typename T>
class Box {
private:
T value; // Data member of type T
public:
Box(T val) : value(val) {} // Constructor to initialize value
T getValue() const { return value; } // Getter to return value
};
int main() {
// Create instances of Box with different types
Box<int> intBox(10);
Box<double> doubleBox(3.14);
Box<string> stringBox("Hello, Template!");
// Display the values
cout << "Integer box: " << intBox.getValue() << endl;
cout << "Double box: " << doubleBox.getValue() << endl;
cout << "String box: " << stringBox.getValue() << endl;
return 0;
}
Output:
Integer box: 10
Double box: 3.14
String box: Hello, Template!
Box class template can store and return values of any type, such as int, double, and string.Box<int>, Box<double>, and Box<string>, the compiler automatically generates the correct version of the Box class for each type.getValue function returns the stored value of type T (which could be any type like int, double, etc.).You can create a class template that takes multiple template parameters to allow more flexibility.
template <typename T, typename U>
class Pair {
private:
T first;
U second;
public:
Pair(T f, U s) : first(f), second(s) {} // Constructor
T getFirst() const { return first; } // Getter for first
U getSecond() const { return second; } // Getter for second
};
int main() {
Pair<int, double> p1(10, 3.14); // Pair of int and double
Pair<string, char> p2("Hello", 'A'); // Pair of string and char
cout << "Pair 1: " << p1.getFirst() << ", " << p1.getSecond() << endl;
cout << "Pair 2: " << p2.getFirst() << ", " << p2.getSecond() << endl;
return 0;
}
Output:
Pair 1: 10, 3.14
Pair 2: Hello, A
Pair class template accepts two types, T and U. We can create instances of Pair with different combinations of types, such as Pair<int, double> or Pair<string, char>.Just like function templates, class templates can have default arguments for the template parameters. If no type is provided when creating an instance of the class, the default type is used.
template <typename T = int>
class Box {
private:
T value;
public:
Box(T val) : value(val) {}
T getValue() const { return value; }
};
int main() {
Box<> defaultBox(5); // Default type 'int'
Box<double> doubleBox(3.14); // Explicit type 'double'
cout << "Default Box: " << defaultBox.getValue() << endl;
cout << "Double Box: " << doubleBox.getValue() << endl;
return 0;
}
Output:
Default Box: 5
Double Box: 3.14
Box has a default template parameter T = int. If no type is specified when an object is created, int is used as the default type.Box<> creates a Box<int> object, and Box<double> creates a Box object that stores double values.A class template can have member functions that use template parameters. These functions can either be defined inside the class definition or outside it.
template <typename T>
class Box {
private:
T value;
public:
Box(T val) : value(val) {}
void setValue(T val) { value = val; }
T getValue() const { return value; }
};
template <typename T>
class Box {
private:
T value;
public:
Box(T val);
void setValue(T val);
T getValue() const;
};
// Member function definitions outside the class
template <typename T>
Box<T>::Box(T val) : value(val) {}
template <typename T>
void Box<T>::setValue(T val) {
value = val;
}
template <typename T>
T Box<T>::getValue() const {
return value;
}
Template specialization allows you to define a specific implementation of a class template for a particular type. For example, you might want to handle a specific data type differently from others (e.g., if the template parameter is int, use a specialized version).
#include <iostream>
using namespace std;
// General template
template <typename T>
class Box {
private:
T value;
public:
Box(T val) : value(val) {}
T getValue() { return value; }
};
// Specialization for type int
template <>
class Box<int> {
private:
int value;
public:
Box(int val) : value(val) {}
int getValue() {
cout << "Specialized Box for int" << endl;
return value;
}
};
int main() {
Box<double> b1(3.14); // Uses the general template
Box<int> b2(42); // Uses the specialized template
cout << "Box with double: " << b1.getValue() << endl;
cout << "Box with int: " << b2.getValue() << endl;
return 0;
}
Output:
Box with double: 3.14
Specialized Box for int
Box with int: 42
Box class template has a general template, but a specialized version is created for int. When we create a Box<int> object, the specialized version is used, which can include additional logic or behavior specific to int.Code Reusability: You can use a single class to handle multiple types of data, which reduces code duplication.
Type Safety: Since templates are type-checked at compile-time, you are guaranteed that the types match when you instantiate the class.
Flexibility: Class templates provide a high level of flexibility, allowing you to create generic containers, algorithms, and data structures.
Extensibility: New types can be added without modifying the class definition, making the code extensible and easy to maintain.
Code Bloat: Every time a class template is instantiated with a new type, a new class is generated. This can lead to code bloat if many instantiations are used.
Compilation Time: Templates can increase compilation time since the code must be generated for each type the class is instantiated with.
Complex Error Messages: Template errors, especially when dealing with complex templates or template specialization, can lead to complicated and hard-to-understand error messages.
template <typename T> syntax, where `TOpen this section to load past papers