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

2024-04-05

当我调查 Qt 的源代码时,我发现 trolltech 的人明确使用this关键字来访问析构函数上的字段。

inline ~QScopedPointer()
{
    T *oldD = this->d;
    Cleanup::cleanup(oldD);
    this->d = 0;
}

那么,这种用法有什么意义呢?有什么好处吗?

编辑:对于那些投票结束这个问题的人,我怀疑这种用法适用于某些类继承情况

一部分QScopedPointer 类 http://qt.gitorious.org/qt/qt/blobs/4.7/src/corelib/tools/qscopedpointer.h#line97定义:

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. 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>有时作为已知的完整类,有时作为不一致的未知类,嗯,你是对的。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在模板化派生类中,为什么需要在成员函数内使用“this->”限定基类成员名称? 的相关文章

随机推荐

  • 四人帮 - 设计模式 - 这些模式示例是否以过时的方式编码?

    所以为了澄清我的问题 臭名昭著的 GoF 书中的每个模式 设计模式 可重用的面向对象软件的元素 有 C 代码示例 这些是最新的吗 或者现在的 C 代码看起来有很大不同吗 我这么问是因为当我发布带有最后一个问题的代码时 许多 C 开发人员告诉
  • 九补丁与矢量图形

    我正在学习 Android UI 但不清楚为什么人们在可以使用矢量图形的情况下使用九个补丁 因为它们是可扩展的 不会出现任何像素退化 我是 Android 的初学者 所以我希望我在这里不会遗漏任何东西 但似乎构建矢量图形并使用它们会更容易
  • 为什么部分应用函数会延迟 Scala 中的类实例化?

    想象一下这段代码 class Foo println in Foo def foo a Int a 1 现在 如果我们调用 new Foo foo 将按预期创建 Foo 类的实例 in Foo res0 Int gt Int
  • Reactjs 地图函数不渲染组件

    这是错误 https i stack imgur com zmiR6 png我正在尝试渲染 createCardHotels 函数 但是 每当我运行它时 什么也没有显示 任何帮助将不胜感激 我使用地图函数来循环数据 每当我运行它时 我都可以
  • Android Studio找不到颜色样式资源

    我正在尝试使用自定义主题 AppCompat NoActionBar但是IDE throws无法找到指定资源的错误 请协助 任何帮助将不胜感激 styles xml如下
  • 网格对于 kernelUD /getverticeshr/adehabitatHR 家庭范围估计来说太小

    adehabitat HR 的文档建议使用以下代码来在创建 UD 对象后计算家庭范围的 95 内核 Calculation of the 95 percent home range ver lt getverticeshr ud 95 对于
  • 发送同步请求角度6 [关闭]

    Closed 这个问题需要细节或清晰度 help closed questions 目前不接受答案 我想在 Angular 6 中发送这个嵌套 for 循环的同步请求 所有 for 循环都必须等待彼此响应 请举一些例子https stack
  • 如何访问iframe元素?

    当您像这样循环访问页面中的所有 iframe 时 HTML ul li li li li li li ul JS for var i 0 i lt window frames length i if window frames i getN
  • Verilog 中的大括号是什么意思?

    我很难理解 Verilog 中的以下语法 input 15 0 a 16 bit input output 31 0 result 32 bit output assign result 16 a 15 a 15 0 我知道assign语句
  • 如何获取两个日期之间的天数?

    我需要计算两个日期之间的天数 我已经检查了此链接给出的代码如何使用 JavaScript 计算两个日期之间的天数 https stackoverflow com questions 2627473 how to calculate the
  • 删除名为“NA”的列

    我正在处理一些 RNA seq 计数数据 其中大约有 60 000 列包含基因名称 24 行包含样本名称 当我进行一些基因名称转换时 我留下了一堆名为NA 我知道 R 可以处理NA与典型的列名称不同 我的问题是如何删除这些列 这是我的数据的
  • Chrome 无法获取选定的 html 字符串换行标签 (contenteditable)

    我在用着this https stackoverflow com a 6668159 1491124Tim Down 的解决方案在 contenteditable div 中获取选定的 html 并且工作正常 谢谢 Tim 但是使用 Chr
  • 显示 2 行消息弹出 vba 6

    有没有办法在 vba 6 的弹出窗口上显示 2 或 3 或 4 或 n 行消息 目前我的弹出窗口 调用 MsgBox 函数 显示如下消息 You did something wrong Please enter valid input 我希
  • ES6 箭头函数和 Promise Chaining 精简语法解释

    在下面的代码块中 有人可以提供压缩警报语句语法的链接或解释吗 我理解前面的扩展等效代码已被注释掉并包含消息参数 但是 我找不到省略消息参数的语法参考 let timeoutPromise new Promise resolve reject
  • Pycharm不显示结果

    Pycharm不显示结果 进程已完成 退出代码为 1 但是当我调试它的工作并显示警告时 Debugger speedups using cython not found Run C Python27 python exe C Program
  • C# COM 自动化的双接口和仅调度接口之间的区别

    我正在针对 C COM 服务器实现一个 C COM 客户端 当我将 COM 接口标记为 Dual 时 COM 客户端可以正常工作 但当我删除 Dual 属性时 它会抛出 InvalidCastException 因此 对我来说最简单的解决方
  • PHP 8 严格类型强制应用于本机函数?

    我的代码适用于 PHP 7 round microtime 3 但在 PHP 8 中 致命错误 未捕获类型错误 round 参数 1 num 必须是 int float 类型 4 中给出的字符串堆栈跟踪 0 round 0 21066100
  • 嵌套 ng-repeat 性能

    我听说嵌套 ng repeats 会严重影响 Angular 的性能 如果它会导致大量带有 Angular 表达式的元素 我实际上已经遇到过这种情况 我正在尝试编写一些代码 我尝试使用bindonce https github com Pa
  • R - 从字符串右侧第 n 次出现字符后提取信息

    我见过很多次提取w gsub但它们主要处理从左到右或在一次出现后提取 我想从右到左匹配 数四次出现 匹配第 3 次和第 4 次出现之间的所有内容 例如 string outcome here are some words to try so
  • 在模板化派生类中,为什么需要在成员函数内使用“this->”限定基类成员名称?

    当我调查 Qt 的源代码时 我发现 trolltech 的人明确使用this关键字来访问析构函数上的字段 inline QScopedPointer T oldD this gt d Cleanup cleanup oldD this gt