Class Derived From a Templated Base Class
As I am learning and writing C++, I encounter the problem where there are two classes having similar function but using different object type. These classes are from a library I am using for the gesture recognition. Some functions with input/output arguments between two classes are same but some are not. And I don’t want to write two different classes with having more or less same functions. And I thought there might be some way to solve as I need to become accustomed to DRY (don’t repeat yourself) principle. Because I never use template before, I need to write a small program to test out my idea.
Explanation
In the following program,
A
is base class and, B
and C
are derived classes. A
class is templated and B
and C
are just regular classes.
About class A
In base class A
, you will notice that template<class T1, class T2>
keyword. This is the indication that the class has been templated. We are using two template types as T1
and T2
here. It has two overloading methods called method
which accept different type as template parameter. The method will print out the input type using typeid(t).name()
so that we know which types are actually pass through the function.
About class B
and C
Both B
and C
are derived class which derived from class A
. When we derived class B
from class A
, class B
is set to use two types only which are int
and double
. This can be seen in this line class B : public A <int, double>
. Therefore, class B
only can accept as int
as first template type and double
as second template type. This is ensure that the method of class A
can handle these template types when we first create the class B
. Similarly, class C
is derived from class A
with <std::string, char>
as template types.
Note: Some IDE will check whether the template function call is compatabile with the type that you pass into the function at compile time. This will save you a lot of headache.
#include <iostream>
#include <typeinfo>
template <class T1, class T2>
class A {
public:
void method(T1 t) {
std::cout << "print from first function! ";
std::cout << "Type is " << typeid(t).name() << std::endl;
}
void method(T2 t) {
std::cout << "print from second function! ";
std::cout << "Type is " << typeid(t).name() << std::endl;
}
};
class B : public A <int, double> {
public:
void print() {
std::cout << "print from from class B!\n";
}
};
class C : public A <std::string, char> {
//class C : public A<bool , char>{
public:
void print() {
std::cout << "print from from class c!\n";
}
};
int main(int argc, char *argv[]) {
B b;
b.method(5.5); // as double type
b.method(5); // as int type
b.print();
C c;
c.method('k'); // 'k' as char type
c.method("stringTest"); // "stringTest" as string type
c.print();
return 0;
}
The output result
print from second function! Type is d
print from first function! Type is i
print from from class B!
print from second function! Type is c
print from first function! Type is Ss
print from from class c!
Overloaded method is Ambiguous
Note that when we try to overload the function with something ambiguous then obviously we will have error like this. error: call of overloaded ‘method(int)’ is ambiguous
. We can try with the following line of code if you want to feel the error.
///this will cause ambiguous error
class C : public A <bool , char> {
...
}
Since both 0
and 1
can be represented as int
type and bool
type, the method don’t know whether to call bool
function for class C
or int
function from class B
.
Alternative inheritance
If you sure that base class can handle different generic types without explicitly needing to mention as class B : public A <int, double>
in derived class, then we can use class B
to accept different type as like the following.
template<class T1, class T2>
class B : public A <T1, T2> {
public:
void print() {
std::cout << "print from from class B!\n";
}
};
After we changed the entire class B with the above code, we cannot just instantiate class B
as B b;
in main routine. We have to call something like this. B <int,double> b;
. This will force to use int
and double
type and the output will be exactly same as previous one.
At main(), we should instantiate B like the following code.
B <int,double> b;
b.method(5.5);
b.method(5);
b.print();
Note: The different between
B b;
andB <int, double
is that the template types are decided when derived from class A for the former one. Whereas, the template types are only decided at main() for the latter one.