'this'指针的类型

时间:2011-05-20 03:44:59

标签: c++ class this-pointer

正如标题中所提到的,我想知道'this'指针的类型。

我正在开发一个项目,我在使用VC ++ 2008的Windows上观察到'this'指针的类型为"ClassName * const this"。我想知道是什么需要/要求这个指针是一个常量指针。感谢。

4 个答案:

答案 0 :(得分:47)

此指针的类型是ClassName *const ClassName *,具体取决于它是否在类ClassName的非const或const方法中进行检查。指针this不是左值。

class ClassName {
  void foo() {
    // here `this` has `ClassName *` type
  }

  void bar() const {
    // here `this` has `const ClassName *` type
  }
};

您上面提到的观察结果具有误导性。指针this 不是左值,这意味着它不可能具有ClassName * const类型,即它不可能在{{的右侧有const 1}}。指针类型的非左值不能是const或非const。在C ++语言中根本没有这样的概念。你观察到的必须是特定编译器的内部怪癖。形式上,这是不正确的。

以下是语言规范(强调我的)的相关引用

  

9.3.2此指针

     

在非静态(9.3)成员函数的主体中,关键字是   一个prvalue表达式,其值是对象的地址   调用该函数。 在成员函数中的类型   X类是X *。如果成员函数声明为const,则为   这是const X *,如果成员函数声明为volatile,则   这个类型是volatile X *,如果声明了成员函数   const volatile,这个类型是const volatile X *。 [注意:因此在   const成员函数,调用该函数的对象   通过const访问路径访问。 - 后注]


在C ++ 98 / C ++ 03中,有几个编译器使用内部实现技巧,这是值得的:他们将*指针解释为常量指针,例如: this在类ClassName *const的非常量方法中。这显然有助于他们确保ClassName的不可修改性。已知GCC和MSVC已经使用该技术。这是一个无害的伎俩,因为在语言层面this不是左值,而且它的常数是不可检测的。额外的this通常只会在编译器发出的诊断消息中显示出来。

然而,随着C ++ 11中rvalue引用的出现,有可能在const的类型上检测到这个额外的const。例如,以下代码在C ++ 11中有效

this

然而,它仍然无法在仍然使用上述技巧的实现中进行编译。 GCC此后放弃了该技术。 MSVC ++仍然使用它(自VS2017起),这阻止了上述完全有效的代码在MSVC ++中编译。

答案 1 :(得分:3)

const表示你无法改变指针指向的内容。

ClassName *const

有很大不同
const ClassName *

后者是指向对象的指针,无法修改对象(无论如何都使用指针)。前者是一个指针,不能重新指向另一个对象(也不是NULL),至少不要求助于讨厌的转换。

当然也有组合:

const ClassName *const

这将是一个无法更改为指向其他内容的指针,也不能用于更改它指向的对象。

至于为什么你的编译器将this指针显示为const,有意义的是你不要让this指向除了它之外的对象。

答案 2 :(得分:1)

上面有很多讨论,主要帖子没有提供正确答案。 人们可能不会挖掘评论,因此最好分享为主要端口(PS)。

我对Ubuntu以及VC ++进行了一些调查,但没有正确的输出(使用typeid(X).name)。


类类型X的成员函数的this指针类型是X * const。如果使用const限定符声明成员函数,则类X的该成员函数的this指针的类型是const X * const。 MSDN link


从概念上讲这也是正确的,因为普通成员函数是“X * const”,这就是为什么它不是l值(因为你不能改变它的内容)。

答案 3 :(得分:-3)

摘自C ++ Primer 4th ed:“在普通的nonconst成员函数中,this的类型是const pointer类型的class。我们可能会更改this指向但不能更改this所占地址的值。在const成员函数中,this的类型为const pointer const class - 类型对象。我们可能既不会更改this指向的对象,也不会更改this所持有的地址。“这意味着VC ++ intellisense显示的是正确的。