Search code examples
c++classtemplatesvirtual

Virtual function in class template, that doesn't have the template type as parameter/return value


As far as I know, templated virtual functions aren't allowed/possible due to the undefined size of the vtable.

On the other hand, virtual functions inside a class template which don't use the template type seem to be allowed, right?

What about a virtual function that doesn't use the template type as parameter or return type but works on data of the template type? Would that be valid C++?

I have already done some testing and it seems to work.

My Code looks like this:

(Note: For reasons of readability this is only the basic structure, not the real code).

template<typename T>
class Base {
public:
    virtual bool compare(void) {
        // Basic implementation
        return ((value1 + value2) < value3);
    }
protected:
    T value1, value2, value3;
}


/**
 * Derived from Base<ComplexClass> where
 * ComplexClass is a Class providing
 * a int Value through .getInt()
**/
class Derived : Base<ComplexClass> {
    bool compare(void) {
        return ((value1.getInt() + value2.getInt()) < value3.getInt());
    }
}

main {
    Base<int> *intBase = new Base<int>();
    Base<double> *doubleBase = new Base<double>();
    Base<ComplexClass> *complexBase = new Derived();

    intBase->compare(); // Should call base function
    doubleBase->compare(); // Should also call base function
    complexBase->compare(); // Should call the compare function of Derived
}

As far as i can tell this works like I excepted. Is this just a lucky coincidence or is this valid/good C++ style?

If it's valid, could someone please explain what's happening inside and why some people say it's forbidden/bad practice to derive from class templates and use virtual functions inside of class templates?

Thank you in advance!

PS: I know something similar could have been done by template specialization but I'd like to know if it's also possible this way.


Solution

  • Q As far as I know, templated virtual functions aren't allowed/possible due to the undefined size of the vtable.

    A You can have virtual function in class templates.

    Example code that compiles and links:

     template <typename T>
     struct Base
     {
        virtual T doSomething(T const& in) = 0;
        Base(T const& data) : data_(data) {}
        T data_;
     };
    
     struct Concrete : public Base<int>
     {
        Concrete(int d) : Base(d) {}
    
        virtual int doSomething(int const& in)
        {
           return data_*in;
        }
     };
    
     int main()
     {
        Concrete a(20);
        int b = a.doSomething(10);
     }
    

    Q On the other hand, virtual functions inside a class template which don't use the template type seem to be allowed, right?

    A The virtual functions of a class template can use anything -- not restricted to not using the template tye.

    My example should make that clear.

    Q What about a virtual function that doesn't use the template type as parameter or return type but works on data of the template type? Would that be valid C++?

    A Yes, it will.

    Again, my example should make that clear.

    EDIT: Extended example

     template <typename T>
     struct Base
     {
        virtual T fun1(T const& in) = 0;
    
        virtual T fun2(int in) = 0;
    
        virtual int fun3(T const& in) = 0;
    
        virtual int fun4(int in) = 0;
    
        Base(T const& data) : data_(data) {}
        T data_;
     };
    
     struct Concrete : public Base<int>
     {
        Concrete(int d) : Base(d) {}
    
        virtual int fun1(int const& in)
        {
           return data_*in;
        }
    
        virtual int fun2(int in)
        {
           return fun1(in);
        }
    
        virtual int fun3(int const& in)
        {
           return fun1(in);
        }
    
        virtual int fun4(int in)
        {
           return fun1(in);
        }
     };
    
     int main()
     {
        Concrete a(20);
        int b = a.fun1(10);
        int c = a.fun2(10);
        int d = a.fun3(10);
        int e = a.fun4(10);
     }