Dependent bases, virtual functions, what does this call? Saturday 11th April 2009
Suppose we have an instance of MoreDerived, and we call the member function g on it. Which f gets called, and what syntax do we need in g to call the other f’s?
// test.cc void f(); template< class T > class Base { public: virtual void f(); }; template< class T > class Derived : public Base< T > { public: void g() { f(); // which f does this call? } }; class MoreDerived : public Derived< int > { void f(); };
The answer is that it calls the global function f. The reason (or ‘problem’) is that in the expression “f();”, the identifier f is a non-dependent name. It does not depend on the template parameter, so lookup occurs at the point of definition of g, not at the point of instantiation of the template. Because the base class is dependent on the type of the template parameter it is not used to resolve f. The only visible f is, therefore, the global f.
To call the base class’ f, we just use a qualified identifier:
void g() { Base<T>::f(); }
As usual, this disables the virtual function mechanism and a direct call to the base class’ f is made.
How do we ensure that the correct virtual f is called? We need to call f through a pointer or reference which is dependent on the template parameter so that the base class is used in the lookup of f at the point of instantiation.
This means something like:
void g() { Base<T>& baseref = *this; basethisref.f(); }
or
void g() { Base<T>* basethis = this; basethis->f(); }
It’s actually enough to just do this:
void g() { this->f(); }
“this” is type-dependent because g is a member function of a class template, so “this->f()” is a type-dependent expression because it has “this” as a type-dependent subexpression.
So now I have to check very carefully before berating my colleagues for writing this->f() rather than just f().
Just ask them if they are accessing a member of a dependent base via an otherwise non-dependent expression. If they look blank, then it’s your queue to shout: “so why are you using ‘this->’?”.
I made this point on a SO question, but it’s so low down that no-one’s even bothered to downvote it.
They always look blank.
In which case you have a different set of problems and a diktat of ‘never use this->’ is an acceptable stance as the chances of them being in a situation where ‘this->’ is required and not understanding that the diktat can and should be ignored is vanishingly small. (Assuming that, like me, you are against unnecessary ‘this->’ which is often a sign of over-reliance on so-called ‘intellisense’.)
I could live with it if it were everywhere. It is the inconsistency that hurts me.
Python requires ‘self.’, which is fine. Nice and explicit.