In my previous article i wrote on function templates, Now i'm going to be writing on Class templates in C++.
WHAT ARE CLASS TEMPLATES?
Class Template can be referred to as blueprints that enable us to create a kind of specialized class with generic constructors, methods, destructors and more. We have a class Student
:
class Student{
private:
std::string temp;
int data;
public:
Student(std::string t, int d){
temp = t;
data = d;
}
int getdata(){
return data;
}
std::string getstring(){
return temp;
}
};
and we want to model another class that's just like this one but has a string
and a double
as it's data members, normally we could just write another class with the same content but with a different name and change the int
to double
but that can get tedious and lengthy especially when it's a class with lots of content and it can make your code look unappealing, but class templates make things so much easier because we can write just one class that will serve as a template if we need a similar class, lets do that with the Student
class:
#include <iostream>
template<typename S>
class Student{
template<typename T> //this is for the overloading of the << operator
friend std::ostream &operator<<(std::ostream &os, const Student<T> &rhs);
private:
std::string temp;
S data;
public:
Student(std::string t, S d){
temp = t;
data = d;
}
S getdata() const{
return data;
}
std::string getstring() consr{
return temp;
}
};
template<typename S> //another template is needed since the ones above can't be reused
std::ostream &operator<<(std::ostream &os, const Student<S> &rhs){
os << "Name: " << rhs.getstring() << " Data: " << rhs.getdata();
return os;
}
I overloaded the stream insertion
<<
operator so i can outputStudent
objects easierI suggest you read the former article on function templates before this one
We create a template parameter template<typename S>
that will be used to make the data
attribute in the class able to model any data type, so we replaced the int
with our template parameter S
and that's basically it, now we can create a Student
object that will have the ability to have a string
with a double
, float
, other data types, now we create a Student
object like this:
int main(){
Student<double> padawan{"Padawan", 3.6};
std::cout << padawan.getdata() << std::endl; //3.6
Student<std::string> erik{"erik", "human"};
std::cout << erik.getdata() << std::endl; //human
Student<Student<int>> casey{"casey", {"glory", 16}};
std::cout << casey.getstring() << std::endl; // casey
std::cout << casey.getdata() << std::endl; // Name: glory Data: 16
//or
std::cout << casey.getdata().getstring() << std::endl; // glory
std::cout << casey.getdata().getdata() << std::endl; // 16
return 0;
}
Now you can see how easy it was for me to create a Student
object that could model a string
and other data types, you can make the two attributes to be templates, i.e X temp
and S data
but you would have to add that to the template parameter template<typename X, typename S>
so the compiler knows what X
is. Notice that i even modeled a Student object with a string
and another Student
object in it, if you can utilize it these templates properly it can save you writing a lot of unnecessary code, Also the syntax we used in creating these Student
objects might look familiar to when you create a vector
object like std::vector<int> vec{1,2,3};
, that's because vectors too are also template classes behind the scenes, the same goes for other C++ containers like deques, maps, links e.t.c. So that's it, this a just a basic look into class templates, it can get very complex when you mix in stuff like inheritance, polymorphism e.t.c. Here's the source code for what i showed you so far in case you want to copy it into your IDE:
#include <iostream>
template<typename S>
class Student{
template<typename T>
friend std::ostream &operator<<(std::ostream &os, const Student<T> &rhs);
private:
std::string temp;
S data;
public:
Student(std::string t, S d) :temp{t}, data{d}{
}
S getdata() const{
return data;
}
std::string getstring() const{
return temp;
}
};
template<typename S>
std::ostream &operator<<(std::ostream &os, const Student<S> &rhs){
os << "Name: " << rhs.getstring() << " Data: " << rhs.getdata();
return os;
}
int main(){
Student<double> padawan{"Padawan", 3.6};
std::cout << padawan.getdata() << std::endl; //3.6
Student<std::string> erik{"erik", "human"};
std::cout << erik.getdata() << std::endl; //human
Student<Student<int>> casey{"casey", {"glory", 16}};
std::cout << casey.getstring() << std::endl; // casey
std::cout << casey.getdata() << std::endl; // Name: glory Data: 16
//or
std::cout << casey.getdata().getstring() << std::endl; // glory
std::cout << casey.getdata().getdata() << std::endl; // 16
return 0;
}
Top comments (0)