简体   繁体   English

在模板派生类中,为什么我需要在成员函数中使用“this->”来限定基类成员名称?

[英]In a templated derived class, why do I need to qualify base class member names with "this->" inside a member function?

While I investigate source code of Qt I saw that trolltech guys explicitly use this keyword to access a field on destructor.当我调查 Qt 的源代码时,我看到 trolltech 人员明确使用this关键字来访问析构函数上的字段。

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: QScopedPointer 类定义的一部分:

template <typename T, typename Cleanup = QScopedPointerDeleter<T> >
class QScopedPointer

C++ answer (general answer) C++ 答案(一般答案)

Consider a template class Derived with a template base class:考虑使用模板基类Derived的模板类:

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 . this具有类型Derived<T> ,一种依赖于T的类型。 So this has a dependent type.所以this有一个依赖类型。 So this->d makes d a dependent name.所以this->d使d成为依赖名称。 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.如果没有this-> ,名称d只会作为非依赖名称被查找,而不会被找到。

Another solution is to declare d in the template definition itself:另一种解决方案是在模板定义本身中声明d

template <typename T>
class Derived : public Base<T> {
    using Base::d;
    void f () {
        d = 0;
    }
};

Qanswer (specific answer) Qanswer(具体答案)

d is a member of QScopedPointer . dQScopedPointer成员 It isn't an inherited member.它不是继承的成员。 this-> is not necessary here. this->在这里不是必需的。

OTOH, QScopedArrayPointer is a template class and d is an inherited member of a template base class: OTOH, QScopedArrayPointer是模板类, d是模板基类的继承成员:

template <typename T, typename Cleanup = QScopedPointerArrayDeleter<T> >
class QScopedArrayPointer : public QScopedPointer<T, Cleanup>

so this-> is necessary here :所以这里- this->是必要的:

inline T &operator[](int i)
{
    return this->d[i];
}

It's easy to see that it's easier to just put this-> everywhere.很容易看出,将this->放在任何地方更容易。

Understand the reason了解原因

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:我想所有 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
    }
};

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) .当模板被实例化时,模板可以具有后期绑定的名称:例如f in f (this) At the point of Derived2::f() definition, there is no variable, function or type name f known by the compiler.Derived2::f()定义点,编译器不知道变量、函数或类型名称f The set of known entities that f could refer to is empty at this point.此时f可以引用的已知实体集是空的。 This isn't a problem because the compiler knows it will lookup f later as a function name, or a template function name.这不是问题,因为编译器知道它稍后会查找f作为函数名或模板函数名。

OTOH, the compiler doesn't know what to do with d ; OTOH,编译器不知道如何处理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?真正的问题似乎是:为什么不是d势必Base<T>::d在模板定义的时间?

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!真正的问题是在模板定义时没有Base<T>::d ,因为当时没有完整的类型Base<T>Base<T>已声明,但未定义! 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 .编译器可以查找dBase<T>对于任何特定的类型T ,但它不能查找d在类模板Base Until a type T is determined, Base<T>::d remains the abstract Base<T>::d ;在确定类型T之前, Base<T>::d仍然是抽象Base<T>::d only when type T is known, Base<T>::d start to refer to a variable of type int .仅当类型T已知时, Base<T>::d开始引用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 .这样做的结果是类模板Derived2有一个完整的基类Base0但是一个不完整的(前向声明的)基类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.仅对于已知类型T ,“模板类”(类模板的特化) Derived2<T>具有完整的基类,就像任何普通类一样。

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.这是非常不同的:这里dDerived<T>的限定名称,而Derived<T>是依赖的,因为T是模板参数。 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.如果您认为在Derived<T>的定义中,有时将Derived<T>视为已知的完整类,而有时将其视为未知的类,则不一致,那么,您是对的。

I would guess it pertains to an overloaded use of the Cleanup() routine.我猜这与 Cleanup() 例程的过载使用有关。 The type being passed is explicitly controlled by the template type T, which in turn can control which overloaded version of Cleanup() is invoked.传递的类型由模板类型 T 显式控制,而模板类型 T 又可以控制调用 Cleanup() 的哪个重载版本。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM