C++答案(一般答案)
考虑一个模板类Derived
具有模板基类:
template <typename T>
class Base {
public:
int d;
};
template <typename T>
class Derived : public Base<T> {
void f () {
this->d = 0;
}
};
this
有类型Derived<T>
,一个类型取决于T
. So this
有依赖类型。所以this->d
makes d
从属名称。从属名称在模板定义的上下文中作为非从属名称以及在实例化的上下文中进行查找。
Without this->
, 名字d
只会作为非依赖名称进行查找,而不会被发现。
另一种解决方案是声明d
在模板定义本身中:
template <typename T>
class Derived : public Base<T> {
using Base::d;
void f () {
d = 0;
}
};
Qanswer(具体答案)
d
is a 成员QScopedPointer http://qt.gitorious.org/qt/qt/blobs/4.7/src/corelib/tools/qscopedpointer.h#line167。它不是继承的成员。this->
这里没有必要。
OTOH, QScopedArrayPointer是一个模板类并且d是模板基类的继承成员: http://qt.gitorious.org/qt/qt/blobs/4.7/src/corelib/tools/qscopedpointer.h#line189
template <typename T, typename Cleanup = QScopedPointerArrayDeleter<T> >
class QScopedArrayPointer : public QScopedPointer<T, Cleanup>
so this->
是必要的here http://qt.gitorious.org/qt/qt/blobs/4.7/src/corelib/tools/qscopedpointer.h#line198:
inline T &operator[](int i)
{
return this->d[i];
}
很容易看出,直接放就更容易了this->
到处。
了解原因
我想所有 C++ 用户都不清楚为什么在非依赖基类中查找名称而不是在依赖基类中查找名称:
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
}
};
除了“标准是这么说的”之外,还有一个原因:模板中名称绑定的工作方式的原因。
模板可以具有稍后绑定的名称,当模板实例化时:例如f
in f (this)
。在点Derived2::f()
定义,没有变量、函数或类型名称f
被编译器知道。已知实体的集合f
此时可以引用的是空的。这不是问题,因为编译器知道它会查找f
稍后作为函数名称或模板函数名称。
OTOH,编译器不知道该怎么办d
;它不是一个(称为)函数名称。无法对非(被调用)函数名称进行后期绑定。
现在,所有这些看起来似乎都是编译时模板多态性的基础知识。真正的问题似乎是:为什么不呢?d
势必Base<T>::d
在模板定义时?
真正的问题是没有Base<T>::d
在模板定义时,因为没有完整的类型Base<T>
当时:Base<T>
已声明,但未定义!你可能会问:那这个呢:
template <typename T>
class Base {
public:
int d;
};
看起来像是一个完整类型的定义!
实际上,在实例化之前,它看起来更像是:
template <typename T>
class Base;
给编译器。无法在类模板中查找名称!但仅限于模板专业化(实例化)。模板是一个将模板专业化的工厂,模板不是一组模板专业化。编译器可以查找d
in Base<T>
对于任何特定类型T
,但它不能
抬头d
在类模板中Base
。直到一个类型T
决心,决意,决定,Base<T>::d
仍然是摘要Base<T>::d
;仅当键入T
已知,Base<T>::d
开始引用类型变量int
.
这样做的后果是类模板 Derived2
有一个完整的基类Base0
但是一个不完整的(前向声明的)基类Base
。仅适用于已知类型T
,“模板类”(类模板的特化)Derived2<T>
有一个完整的基类,就像任何普通类一样。
您现在看到:
template <typename T>
class Derived : public Base<T>
实际上是一个基类规范模板(制定基类规范的工厂)遵循与模板内的基类规范不同的规则。
评论:
读者可能已经注意到,我在解释的最后杜撰了一些短语。
这是非常不同的:这里d
是一个限定名称Derived<T>
, and Derived<T>
是依赖的,因为T
是一个模板参数。即使限定名称不是(被调用的)函数名称,也可以进行后期绑定。
还有一个解决方案是:
template <typename T>
class Derived : public Base<T> {
void f () {
Derived::d = 0; // qualified name
}
};
这是等价的。
如果您认为在定义内Derived<T>
, 治疗Derived<T>
有时作为已知的完整类,有时作为不一致的未知类,嗯,你是对的。