Class Derived From a Templated Base Class

Class Derived From a templated base class.md

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; and B <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.