C++中的this指针类型

10

可能听起来很蠢,在C++prime第五版P258中,它说:

 

默认情况下,this的类型是指向类类型的非const版本的const指针。例如,默认情况下,在Sales_data成员函数中,this的类型是Sales_data * const。

我可以理解this*是一个const指针,这意味着一旦初始化指向的对象不能更改。但随后又说:

 

尽管this是隐式的,但它遵循正常的初始化规则,这意味着(默认情况下)我们不能将this绑定到一个const对象上。

但是我编写了以下代码,它仍然可以正常编译:

```cpp class Sales_data { public: bool is_same(const Sales_data &rhs) const { return this == &rhs; } }; ```

class Test{
public:
    Test() = default;
    Test(const string &s): teststr(" ") {};
    Test(int a) : testint(a) {};
    Test(const string &s, int a): teststr(s), testint(a) {};
    string getstr() const { return teststr; };
    int getint() { return testint; };   //there is no const here
private:
    string teststr;
    int testint = 0;
};

int main(){
    Test a("abc",2);

    cout << a.getint() << " ";
    cout << a.getstr() << endl;
    cout << endl;

    return 0;
}
所以我的问题是:如果编译器可以正常编译它,无论有没有'const',那为什么这很重要呢?然后书上说:毕竟,isbn的主体没有改变指向该对象的内容,所以如果这是一个指向const的指针,我们的函数将更具灵活性。我想知道灵活性是什么? 你能给我举些例子吗?

7
这本书存在误导。this不是一个“const指针”,而是一个关键字,当被评估时会产生适当指针类型的prvalue值。由于它是一个prvalue,你无法修改它,就像你不能说(1+2)=3一样。 - Kerrek SB
13
你混淆了“常量指针”(指向不能指向不同对象的指针)和“指向常量的指针”(指向不能通过指针改变的对象的指针)。请注意区分。 - cdhowie
关于你想要的示例,将 main() 的第一行改为 const Test a("abc",2);,你会发现你不能再调用 getint() 了,但是你仍然可以继续调用 getstr()。不改变对象的方法应该声明为 const,因为这样它们可以在给定一个 const 对象(或引用/指向 const 对象的指针)时使用。 - cdhowie
1
你的报价明确指出:“默认情况下,它的类型是指向类类型的非const版本的const指针。例如,在Sales_data成员函数中,默认情况下,this的类型是Sales_data * const”。 - Daniel
2
你一直在打this*,但这不是正确的写法。请使用纯粹的this - Kate Gregory
可能是Type of 'this' pointer的重复问题。 - legends2k
5个回答

13
对于初学者来说,this通常被描述为一个常量指针。
然而,this实际上是一个指针类型的prvalue(纯右值)。你不能给基本类型的prvalue赋值,这意味着this的“const-ness”。 this的确切类型取决于方法的cv限定符。一个经验法则是将cv限定符简单地放在通常的指针类型前面——即,如果Class的方法标记为const,那么类型就是const Class*

如果编译器可以在有'const'和没有'const'的情况下都编译成功,那么它有什么关系呢?

只有当this的指向类型是const时,你才不能修改类的成员。
Class const* ptr; // ptr->data is also const, not modifiable through this pointer

Class* ptr; // ptr->data isn't const - can be modified.

const 修饰方法允许您区分适用于 const 对象和非 const 对象的方法,这常常是必需的。


7
根据C++标准(9.3.2 The this pointer):
在非静态成员函数中,关键字this是一个prvalue表达式,其值是调用该函数的对象的地址。类X中的成员函数中this的类型为X*。如果成员函数被声明为const,则this的类型为const X*,如果成员函数被声明为volatile,则this的类型为volatile X*,如果成员函数被声明为const volatile,则this的类型为const volatile X*。
正如您所看到的,没有说明this的类型为ClassTYpe * const或ClassType const * const。它是一个prvalue,除了对于类类型的prvalue可以调用非const成员函数之外,不能像任何prvalue一样修改。
至于您混合了两种类型,即指向常量数据的常量指针和指针。例如,以下声明:
const ClassType *p;

没有声明一个常量指针。因此,指针本身可能没有初始化。另一方面,这个声明

ClassTYpe * const p = new ClassTYpe;

声明一个常量指针,且该指针本身应像其他常量一样被初始化。关于你的书中引用的这句话,它意味着最好使用const限定符定义函数。在这种情况下,它可以被调用来处理常量和非常量对象。否则,它只能被调用来处理非常量对象,因为函数内部this指针类型不是const ClassType *

它是一个prvalue,可能不能被修改为任何prvalue。这仅适用于非类类型的prvalues,因此“任何”是错误的。 - Lightness Races in Orbit
@Lightness Races in Orbit 你可以为类类型的prvlaue调用非const成员函数,但不能直接更改类的数据成员。 - Vlad from Moscow
正确,但您可以通过调用成员函数来实现。说您无法修改对象是完全错误的。 - Lightness Races in Orbit

5

"我可以理解,const指针意味着它所指向的对象一旦初始化就不能更改。但是接下来说:

this 是一个 const指针,这意味着你不能像改变指针值本身一样改变它。

 class MyClass {
      void foo() {
          MyClass a;
          this = &a; // <<< Compiler error
      }
 }

this的类型实际上显示为

 MyClass * const this;

对于 const 实例或引用

 MyClass const * const this;

注意这与之不同

 const MyClass* some_const_instance_pointer;

请注意,这与之前不同。 你错了,根本没有任何区别。:) - Vlad from Moscow
尽管你更新了你的帖子,但我还是看不出任何区别。 :) - Vlad from Moscow

5

"灵活性"体现在您可以在任何对象上调用const函数,无论该对象是否为常量。但是您不能在const对象(或对const的引用/指针)上调用非const函数。

因此,以下操作将失败:

const Test c;
cout << a.getint() << " ";   // ERROR: non-const function
cout << a.getstr() << endl;  // OK: const function

除了灵活性外,将一个成员函数声明为const也是一个好主意,因为这样可以防止在不应该修改对象的函数中意外地修改对象。


4
两个问题,两个答案。
在这种情况下,“const”表示“this”指针无法被重新分配。您可以更改“this”指向的对象的内容,但不能更改它所指向的对象。
使方法成为“const”的额外灵活性是它可以用于“const”和非“const”对象。非“const”方法不能用于“const”对象。
示例:
class A {
    int a;
    public:
    int method() const {
        return a;
    }
};

void f() {
    A a;
    const A ca;

    a.method();
    ca.method();
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接