While I investigate source code of Qt I saw that trolltech guys explicitly use this
keyword to access a field on destructor.
inline ~QScopedPointer() { T *oldD = this->d; Cleanup::cleanup(oldD); this->d = 0; }
So, what's the point of this usage? Are there any benefits?
Edit: For those who vote for closing this question, I suspect that this usage is for some class inheritance cases
A part of QScopedPointer class definition:
template <typename T, typename Cleanup = QScopedPointerDeleter<T> > class QScopedPointer
You can use both a structure and a class as base classes in the base list of a derived class declaration: If the derived class is declared with the keyword class , the default access specifier in its base list specifiers is private .
1. A base class is an existing class from which the other classes are derived and inherit the methods and properties. A derived class is a class that is constructed from a base class or an existing class.
The derived class inherits all members and member functions of a base class. The derived class can have more functionality with respect to the Base class and can easily access the Base class. A Derived class is also called a child class or subclass.
Deriving from a non-template base classIt is quite possible to have a template class inherit from a 'normal' class. This mechanism is recommended if your template class has a lot of non-template attributes and operations. Instead of putting them in the template class, put them into a non-template base class.
Consider a template class Derived
with a template base class:
template <typename T> class Base { public: int d; }; template <typename T> class Derived : public Base<T> { void f () { this->d = 0; } };
this
has type Derived<T>
, a type which depends on T
. So this
has a dependent type. So this->d
makes d
a dependent name. Dependent names are looked-up in the context of the template definition as non-dependent names and in the context of instantiation.
Without this->
, the name d
would only be looked-up as a non-dependent name, and not be found.
Another solution is to declare d
in the template definition itself:
template <typename T> class Derived : public Base<T> { using Base::d; void f () { d = 0; } };
d
is a member of QScopedPointer
. It isn't an inherited member. this->
is not necessary here.
OTOH, QScopedArrayPointer
is a template class and d
is an inherited member of a template base class:
template <typename T, typename Cleanup = QScopedPointerArrayDeleter<T> > class QScopedArrayPointer : public QScopedPointer<T, Cleanup>
so this->
is necessary here:
inline T &operator[](int i) { return this->d[i]; }
It's easy to see that it's easier to just put this->
everywhere.
I guess it isn't clear to all C++ users why names are looked-up in non-dependent base classes but not in dependent base classes:
class Base0 { public: int nd; }; template <typename T> class Derived2 : public Base0, // non-dependent base public Base<T> { // dependent base void f () { nd; // Base0::b d; // lookup of "d" finds nothing f (this); // lookup of "f" finds nothing // will find "f" later } };
There is a reason beside "the standard says so": cause of way name binding in templates works.
Templates can have name that are bound late, when the template is instantiated: for example f
in f (this)
. At the point of Derived2::f()
definition, there is no variable, function or type name f
known by the compiler. The set of known entities that f
could refer to is empty at this point. This isn't a problem because the compiler knows it will lookup f
later as a function name, or a template function name.
OTOH, the compiler doesn't know what to do with d
; it isn't a (called) function name. There is no way to do late binding on non-(called) functions names.
Now, all of this may seem like elementary knowledge of compile-time template polymorphism. The real question seems to be: why isn't d
bound to Base<T>::d
at template definition time?
The real issue is that there is no Base<T>::d
at template definition time, because there is no complete type Base<T>
at that time: Base<T>
is declared, but not defined! You may ask: what about this:
template <typename T> class Base { public: int d; };
it looks like the definition of a complete type!
Actually, until instantiation, it looks more like:
template <typename T> class Base;
to the compiler. A name cannot be looked-up in a class template! But only in a template specialisation (instantiation). The template is a factory to make template specialisation, a template isn't a set of template specialisation. The compiler can lookup d
in Base<T>
for any particular type T
, but it cannot lookup d
in the class template Base
. Until a type T
is determined, Base<T>::d
remains the abstract Base<T>::d
; only when type T
is known, Base<T>::d
start to refer to a variable of type int
.
The consequence of this is that the class template Derived2
has a complete base class Base0
but an incomplete (forward declared) base class Base
. Only for a known type T
, the "template class" (specialisations of a class template) Derived2<T>
has a complete base classes, just like any normal class.
You now see that:
template <typename T> class Derived : public Base<T>
is actually a base class specification template (a factory to make base class specifications) that follows different rules from a base class specification inside a template.
Remark: The reader may have noticed that I have made-up a few phrases at the end of the explanation.
This is very different: here d
is a qualified name in Derived<T>
, and Derived<T>
is dependent since T
is a template parameter. A qualified name can be late-bound even if it isn't a (called) function name.
Yet another solution is:
template <typename T> class Derived : public Base<T> { void f () { Derived::d = 0; // qualified name } };
This is equivalent.
If you think that inside the definition of Derived<T>
, the treatment of Derived<T>
as a known complete class sometimes and as an unknown class some other times in inconsistent, well, you are right.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With