MechaTheo
MechaTheo

Reputation: 123

Overriding template methods

I'm trying to override a template method. Here is a minimal example:

#include <iostream>

class Base
{
public:
    template <typename T>
    void print(T var)
    {
        std::cout << "This is a generic place holder!\n";
    }
};

class A: public Base
{
public:
    template <typename T>
    void print(T var)
    {
        std::cout << "This is A printing " << var << "\n";
    }
};

class B: public Base
{
public:
    template <typename T>
    void print(T var)
    {
        std::cout << "This is B printing " << var << "\n";
    }
};


int main()
{
    Base * base[2];
    base[1] = new A;
    base[2] = new B;

    base[1]->print(5);
    base[2]->print(5);

    delete base[1];
    delete base[2];
    return 0;
}

The output is in both cases This is a generic place holder! How can i achieve that the methods of the derived classes are called?

If the method would not be a template, i could define it virtual and it would work as expected (already tried that), but it needs to be a template. So what am i doing wrong?

Upvotes: 2

Views: 6881

Answers (3)

user2913094
user2913094

Reputation: 967

While it wouldn't make sense for unspecialized template methods to be virtual (e.g., what would the vtable look like?), it is worth pointing out that there is no reason that specializations of template methods couldn't be virtual and significant benefits for allowing it. I submitted this to the C++ committee as the final section in N3405. This has not been considered as of yet by the committee, but I have even older papers that are coming up for consideration, so there's still hope :)

Upvotes: 1

Barry
Barry

Reputation: 304017

The reason both calls call Base::print has nothing to do with the fact that print is a template method and everything to do with the fact that it's non-virtual. Regardless of what print was, A::print and B::print would never be considered.

Now the typical solution for actually calling A::print through a Base* would be to simply make print a virtual method. However, this is a no-go since print is a template and you cannot have template virtual methods by rule.

One way around this is type erasure. You can use Boost.TypeErasure to do something like:

typedef any<mpl::vector<
    copy_constructible<>,
    typeid_<>,
    ostreamable<>
> > any_streamable;

struct Base {
    virtual void print(any_streamable var) // not a template!
    {
        std::cout << "This is a generic place holder!\n";
    }        
};

struct A : Base {
    void print(any_streamable var) {
        std::cout << "This is A printing " << var << "\n";
    }
};

For simple things like just streaming, you can write yourself too without needing the library.

Upvotes: 3

Matt
Matt

Reputation: 6050

First A member function template cannot be virtual, and a member function template in a derived class cannot override a virtual member function from the base class.

As your code, the type of the pointer are Base*, so in template member function instantiation, the function in the Base is instantiated, that's why the function is base is called.

If you use A* and B*, the functions in the children will be instantiated and called.

Upvotes: 1

Related Questions