Reputation: 5137
I have a template method in a parent class, that should call another method from the base class. It works, if the method is explicitly defined in the base class, but it doesn't work if the method is inherited. I can't figure out what's exactly wrong with this code (although I know it's a little weird :)
class A
{
protected:
virtual void someMethod()
{
}
template <class TBaseClass>
void templateMethod()
{
TBaseClass::someMethod();
}
};
class B : public A
{
};
class C : public B
{
protected:
virtual void someMethod()
{
templateMethod<A>(); // this works
templateMethod<B>(); // this doesn't
}
};
This ends up with compiler error:
error C2352: 'A::someMethod' : illegal call of non-static member function
What exactly is wrong? I'm not looking for workarounds, that's easy. I'd like to know why is this incorrect.
Upvotes: 1
Views: 571
Reputation: 1487
I think it's not working because you are trying to call a static method. Static methods can be inherited but they can't be virtual. Thats why A::someMethod will work and B::someMethod won"t work.
Upvotes: 0
Reputation: 76246
In template <TBaseClass> void A::templateMethod()
the invocant, this
, is of type A *
. So when you try to call B::someMethod
on it, the compiler won't recognize it a object method call, because B
is not a base class, but it can still be a static method call, so the compiler will try that, find B::someMethod
inherited via A
and complain it is not static. The fact that A
is a base class of this
is not relevant; only that B
is not.
Upvotes: 1
Reputation: 2234
The issue is that class A is not automatically granted access to class B. The methods within the class don't know that the current instance of A is actually of type B.
To do what you're trying, you need to cast A to the target type:
template <class TBaseClass>
void templateMethod()
{
static_cast<TBaseClass*>(this)->someMethod();
}
This will work if the particular instance of A you're calling really is a B (as it is in the example you give). There is no type checking done here to be sure it is. If you pass a class that is not in the inheritance hierarchy you will be in the work of undefined behavior.
That said, your example has "someMethod()" as virtual. If you're doing what I just did here then making that method virtual may not make sense, as you are explicitly saying which instance you want. If you do leave it virtual, then just calling someMethod() directly in A will get you the most derived instance.
Upvotes: 0