Template Classes
Template classes provide a way to create data structures and objects that are independent of the data types they hold. Much like template functions, template classes allow you to write the logic for a single, generic class without tying it to a specific type.
Like in CSCE146, this approach is used to create container classes—such as arrays, vectors, lists, stacks, queues, and strings—that can work with any type of element.
Syntax
Section titled “Syntax”Defining a template class in C++ is conceptually similar to defining a
template function. You begin with a template directive, then declare
one or more type parameters inside angle brackets:
template <class T>class MyClass { public: void MyFunc() { cout << "hello" << endl; } void AnotherFunc() { // do something }
private: // data members};Instantiating A Template Class
Section titled “Instantiating A Template Class”To create an object of a template class, specify the type you want to use in angle brackets when declaring your object:
MyClass<int> intObject;MyClass<std::string> strObject;
intObject.MyFunc();Example
Section titled “Example”You may remember creating a Generic Dynamic Array in CSCE146. Lets create one for CSCE240 using template classes.
-
Create Header
Create you header file, write your header guards, and import everything you need. This dynamic array will keep track of its current size, and capacity and the class will be defined in a namespace called
csce_240:darray.h // Copyright 2024 CSCE240#ifndef D_ARRAY_H#define D_ARRAY_H#include <iostream>using std::cout;using std::endl;namespace csce_240 {template <class T>class DynamicArray {public:// TODOprivate:int size_;int capacity_;T* array_;};} // namespace csce_240#endif -
Constructors and Destructor
Lets create a constructor for the class. We’ll make the initial capacity 10 and double it whenever we need to resize.
We’ll also create a copy constructor and fill the array with the new elements. We also need a destructor since we’re using a pointer as a data member:
darray.h // constructorDynamicArray() : size_(0), capacity_(10), array_(new T[capacity_]) {}// copy constructorDynamicArray(const DynamicArray& el): size_(el.size_), capacity_(el.capacity_), array_(new T[capacity_]) {for (int i = 0; i < size_; ++i) {array_[i] = el.array_[i];}}// destructor~DynamicArray() {if (array_ != nullptr) delete[] array_;} -
Accessors and Operator
Next we’ll define Getters for the size and capacity of the array:
darray.h int GetSize() const { return size_; }int GetCapacity() const { return capacity_; }Since we have a pointer as a data member, we also need to overload the assignment operator:
darray.h // operator overloadDynamicArray& operator=(const DynamicArray& el) {size_ = el.size_;capacity_ = el.capacity_;delete[] array_;for (int i = 0; i < size_; ++i) {array_[i] = el.array_[i];}return *this;} -
Utility Functions
The first utility function to define is a function to print all the elements that were added to the array. We can keep this function public since its especially useful for testing:
darray.h void Print() const {for (int i = 0; i < size_; ++i) {cout << array_[i] << " ";}cout << endl;}We need to implement a way to add elements to the array, but we also have to consider how it will resize. How the array grows is something we can move to the private section of our class. It is a function that should only be called when necessary and an object should not have access to it:
Public
Adddarray.h // public utilitiesvoid Add(T el) {if (size_ == capacity_) {Resize_();array_[size_] = el;capacity_ *= 2;++size_;} else {array_[size_] = el;++size_;}}Private
Resizedarray.h // private utilitiesvoid Resize_() {T* temp = new T[capacity_ * 2];// fill arrayfor (int i = 0; i < size_; ++i) {temp[i] = array_[i];}delete[] array_;array_ = temp;} -
Test
Create a driver file, include the header file, and use the new class we created. We’ll add a couple of elements to an array then print it. We’ll then test the copy constructor and the overloaded assignment operator:
driver.cc // Copyright 2024 CSCE240#include <iostream>#include "darray.h"using csce_240::DynamicArray;using std::cout;using std::endl;int main() {DynamicArray<int> array;for (int i = 0; i < 15; ++i) {array.Add(i);}array.Print();cout << endl;DynamicArray<int> another(array);another.Print();cout << endl;DynamicArray<int> final = another;final.Print();return 0;}Terminal window g++ -Wall -std=c++17 driver.cc./a.out0 1 2 3 4 5 6 7 8 9 10 11 12 13 140 1 2 3 4 5 6 7 8 9 10 11 12 13 140 1 2 3 4 5 6 7 8 9 10 11 12 13 14