在模板派生类中,为什么需要使用成员函数中的"this->"限定基类成员名称?
In a templated derived class, why do I need to qualify base class member names with "this->" inside a member function?
当我调查Qt的源代码时,我看到trolltech的人明确使用this
关键字来访问析构函数上的字段。
inline ~QScopedPointer()
{
T *oldD = this->d;
Cleanup::cleanup(oldD);
this->d = 0;
}
那么,这种用法的意义何在?有什么好处吗?
编辑:对于那些投票支持关闭这个问题的人,我怀疑这种用法适用于某些类继承情况
QScopedPointer 类定义的一部分:
template <typename T, typename Cleanup = QScopedPointerDeleter<T> >
class QScopedPointer
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
的类型。所以this
有一个依赖类型。因此,this->d
使d
成为依赖名称。从属名称在模板定义的上下文中作为非依赖名称以及在实例化上下文中查找。
如果没有this->
,d
这个名字只会被查找为一个非依赖的名字,而不会被找到。
另一种解决方案是在模板定义本身中声明d
:
template <typename T>
class Derived : public Base<T> {
using Base::d;
void f () {
d = 0;
}
};
Q答案(具体答案(
d
是QScopedPointer
的成员。它不是继承的成员。 这里不需要this->
。
OTOH,QScopedArrayPointer
是一个模板类,d
是模板基类的继承成员:
template <typename T, typename Cleanup = QScopedPointerArrayDeleter<T> >
class QScopedArrayPointer : public QScopedPointer<T, Cleanup>
所以这里this->
是必要的:
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;
到编译器。无法在类模板中查找名称!但仅在模板专用化(实例化(中。模板是使模板专用化的工厂,模板不是一组模板专用化。编译器可以在Base<T>
中查找任何特定类型的T
d
,但它不能类模板中的查找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>
中的限定名,Derived<T>
是依赖的,因为T
是一个模板参数。限定名称可以是后期绑定的,即使它不是(调用的(函数名称。
另一种解决方案是:
template <typename T>
class Derived : public Base<T> {
void f () {
Derived::d = 0; // qualified name
}
};
这是等效的。
如果你认为在Derived<T>
的定义中,有时将Derived<T>
视为一个已知的完整类,而在其他时候则作为一个未知类不一致,那么你是对的。
我猜它与 Cleanup(( 例程的重载使用有关。 传递的类型由模板类型 T 显式控制,而模板类型 T 又可以控制调用哪个重载版本的 Cleanup((。
- 将成员变量添加到共享库中的类中,不会破坏二进制兼容性吗
- 对RValue对象调用的LValue ref限定成员函数
- 为什么使用 "this" 指针调用派生成员函数?
- 具有奇怪重复模板模式的派生类中的成员变量已损坏
- 助记符和指向成员语法的指针
- 用于访问容器<T>数据成员的正确 API
- 内置函数可查看CPP中的成员变量
- 是否可以初始化不可复制类型的成员变量(或基类)
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗
- 找不到成员对象:没有名为get_event()的成员,也处理多态性和向量
- 嵌套在类中时无法设置成员数据
- 为什么在没有显式默认构造函数的情况下,将另一个结构封装在联合中作为成员的结构不能编译
- 将函数类成员映射到类本身内部
- 基于另一个成员参数将函数调用从类传递给它的一个成员
- 将Ref对象作为类成员
- 将包含C样式数组的对象初始化为成员变量(C++)
- 静态数据成员的问题-修复链接错误会导致编译器错误
- 将公共但非静态的成员函数与ALGLIB集成
- 多成员Constexpr结构初始化
- 是否需要使用 - &gt;运算符在C 中调用成员函数时