Reputation: 123
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
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
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
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