Class Templates in C++

Class templates in C++

Templates in C++ are of two types


2) Class Templates.

In this article we will learn about class templates.

Class templates are a way through which we can use the same class for different data types. You don't have to write classes with the same functionality again and again for different data types.

A difference between function templates and class templates is that the compiler cannot deduce the data types for the template parameters from the arguments provided by the user in the class template, so you have to explicitly specify the template arguments (data types to use) for the class template.

Defining a Class Template

Following is a basic example of a class template.

 1 
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include<iostream>
using namespace std;

template <typename T>    // template with single parameter T
class calci {
private:
	T first, second;  // two private variables of type T
public:
	calci(T var1, T var2) {      // a constructor with two parameters
		first = var1;        // assigning the argument values
		second = var2;	     // to the private variables
	}	
	T add() {			 // function definition which returns the
		return first + second;	 // the sum of the private variables
	}
	T subtract();		// declaring a function
};

template <typename T>		 // defining function outside the class
T calci<T>::subtract() {	 // provide template parameter of class template
	return first - second;	 // function returns the difference of the private variables
}

int main() {
	calci<int>obj1(10, 20);     // creating an object of class with template argument as "int"
	cout << obj1.add() << endl;	// calling function "add" through object
	cout << obj1.subtract() << endl; // calling function "subtract" through object
	
	calci<double>obj2(10.285, 20.267); // another object with template argument as "double"
	cout << obj2.add() << endl;		   // calling the functions from second object
	cout << obj2.subtract() << endl;
	return 0;
}

In the above example, from line 4, we define the class template. The  definition starts with the keyword template and then in the angular brackets, another keyword typename (which can be substituted by keyword class) and then a placeholder for a data type where we have written T. You can anything instead of T.

We provide a single template parameter T, this T can indicate any data type the user provides as a template argument while creating an object from the class.

template <typename T>    // template with single parameter T

In the class named calci, we declare two private variables, first and second, they are of data type T (T indicates the data type specified by the user at the time of creating an object).

From line 9 we define a constructor (function with same name as of the class and which is executed automatically when an object is created) which is under public access specifier.

calci(T var1, T var2) {      // a constructor which takes two parameters
	first = var1;            // assigning the argument values
	second = var2;		// to the private variables
}

The constructor takes 2 arguments which will be passed when we create an object and assign the values of the arguments to the private variables.

Then from line 13, we define a function named add() which returns the sum of the two private variables first and second. The return type of the function is T.

Here the arguments are supposed to be numerical types (eg. int) or the types which can be converted to a numerical (eg. char).

T add() {	// function definition which returns the
	return first + second;	 // the sum of the private variables
}

On line 16, we declare a function named subtract() which will be defined outside the class.

T subtract();	// declaring a function subtract()

Now outside the class, from line 19, we use the function template format to define a function which was declared inside the class. We didn't use the template format for the function which was defined inside the class.

template <typename T>		 // defining a function outside the class
T calci<T>::subtract() {	 // provide template parameter of class template
	return first - second;	 // function returns the difference of the private variables
}

One thing to note in the second line of the above code is that we have to provide the template parameter just after the class name.

First we write the return type of the function that is T, then the class name followed by the template parameter (in this case <T>) and then we use the scope operator (::) to access the member function of the class. The substract() function returns the difference of the two private variables first and second.

Now in the main() function on line 25, we create an object named obj1

calci<int>obj1(10, 20);     // creating an object of class "calci" with template parameter as "int"

As said, the compiler cannot deduce the data type for the template arguments from the arguments provided in a class template. Hence we have to explicitly specify the data type in the angle brackets just after class name (in this case <int>). And also we have to pass two arguments (int arguments) to the object (as the constructor of the class takes two arguments).

Then on line 26 and 27 we call the add() and subtract() function respectively through the object obj1.

cout << obj1.add() << endl;	// calling functions through object
cout << obj1.subtract() << endl;

Likewise on line 29, we create another object named obj2 of class calci. This time we specify the data type as double and pass two double arguments to the object. Also we call the add() and subtract() function through the object.

calci<double>obj2(10.285, 20.267); // another object with template argument as "double"
cout << obj2.add() << endl;		   // calling the functions from second object
cout << obj2.subtract() << endl;

Defining Class Template with multiple parameters

Below is an example of the a class template with multiple parameters.

 1 
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include<iostream>
using namespace std;

template <typename T, typename U>    // template with two parameters
class test {
private:
	T first;	// private member of type T
	U second;	// private member of type U
public:
	test(T var1, U var2);   // constructor declaration
	void show();		// function declaration
};
template <typename T, typename U>	// multiple parameter template format
test<T, U>::test(T var1, U var2) {	// defining the constructor with two different data type parameters
	first = var1;			// assigning the value of arguments to 
	second = var2;			// the private variables
}
template <typename T, typename U>	// defining function outside the class
void test<T, U>::show() {
	cout  << first << " and " << second << endl;  // has access to private members
}
int main() {
	test<int, string> obj1(10, "Hello World!");  // specifying data types when creating object 
				 // and also passing arguments
	obj1.show();		// calling function through object
	
	test<char, double> obj2('A', 2.3);	// another object with different template arguments
	obj2.show();
	return 0;
}

In above code, we define the class template from line 4, this time we have two template parameters T and U which indicate the data types specified by the user when we create an object of the class. 

template <typename T, typename U>   // template with two parameters

The class is named as test. It has two private variables

private:
	T first;		// private member of type T
	U second;		// private member of type U

variable first is of type T and variable second is of type U

Under the public access specifier, we declare a constructor which has two parameters of type T and U respectively. We also declare a function named show(). Both the constructor and the function are defined outside the class.

Because the constructor is defined outside the class, we have to  write the function template format as from line 13.

template <typename T, typename U>   // multiple parameter template format
test<T, U>::test(T var1, U var2) {   // defining the constructor with two parameters
	first = var1;		// assigning the value of arguments to 
	second = var2;		// the private variables
}

And on the second line in the above code, we have to provide the template parameters after the class name (in this case <T, U>). Then we use the scope operator to access the constructor of the class. Here the constructor takes two parameters - var1 is of type T and var2 is of type U. The values of both the parameters are then assigned to the private variables first and second.

To define the function show() outside the class, again we write the function template format on line 18,

template <typename T, typename U>	// defining constructor outside the class
void test<T, U>::show() {
	cout  << first << " and " << second << endl;  // has access to private members
}

After that on the next line, we write the return type (in this case - void), then comes the class name. As said, we have to provide the template parameters in the angle brackets after the class name and then the scope operator followed by the function name.

This function prints the values of the private variables which were assigned the values of the arguments of the constructor.

Now in the main() function on line 23,

test<int, string> obj1(10, "Hello World!");  // specifying data types when creating object 
  		                // and also passing arguments
obj1.show();			// calling function through object

We create an object named obj1, of the class test. For that we need to write the class name, then in angular brackets, we provided the data types as template arguments of the class template (in this case <int, string>) and then a name for the object to be created. We also provide arguments for parameters to the constructor of the class.

Then on line 25, we call the function show() through the object obj1.

Likewise we create another object named obj2 on line 27, this time we pass the data types as <char, double>.

Default arguments in Class Templates

We shall modify the previous example a little bit to understand default parameters in class templates.

 1 
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include<iostream>
using namespace std;

template <typename T=int, typename U=string>   // specifying default parameters
class test {
private:	
	T first;
	U second;
public:
	test(T var1, U var2);
	void show();
};

template <typename T, typename U>
test<T, U>::test(T var1, U var2) {
	first = var1;
	second = var2;
}

template <typename T, typename U>
void test<T, U>::show() {
	cout  << first << " and " << second << endl;
}

int main() {

	test<> obj1(10, "Hello World!");    // empty angle brackets
	obj1.show();

	test<char, double> obj2('A', 2.3);
	obj2.show();

	return 0;
}

In the above program on line 4, we specify the default template parameters, T as int and U as double. If the template arguments passed are of the same type as the type of the default parameters respectively, the angular brackets can be empty while creating an object of the class.

And as you can notice on line 27, we kept the angular brackets empty because the types of the arguments passed are respectively the same as the default parameter types of the class template (in this case <int, string>).

test<> obj1(10, "Hello World!");    // empty angle brackets

But on line 30, while creating another object of the class, we specify the template arguments as they are different from the default arguments.

In this way we can use class templates in C++.

Comments