user1271373
user1271373

Reputation: 3

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.

Upvotes: 0

Views: 373

Answers (2)

iavr
iavr

Reputation: 7637

This is perfectly valid. However, here you can have the same behaviour with specialization or just overloading, e.g.

template<typename T>
struct Base
{
    bool compare() const { return val(value1) + val(value2) < val(value3); }

protected:
    T value1, value2, value3;

private:
    template<typename U>
    static U val(U a) { return a; }
    static int val(const ComplexClass& a) { return a.getInt(); }
};

Better keep virtual functions for when it's really needed.

And try to gather as much as possible shared code in a single place, minimizing what is to be specialized.

Upvotes: 0

R Sahu
R Sahu

Reputation: 206577

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);
 }

Upvotes: 1

Related Questions