这是什么奇怪的魔法?

What strange magic is *this?

本文关键字:是什么      更新时间:2023-10-16

快速问题。 我想了解*this在C++的行为。 如果这太明显了,或者是一个重复,请原谅我,因为搜索引擎将 * 解释为通配符,我的搜索有点不那么有启发性。

我正在使用别人的代码,它有许多函数,如下所示:

(N 的类型是结构体)

N N::someMethod() const {
N n = *this;
// do a function that modifies internal values of the struct
n.modify();
return n;
}

发生的情况是,它返回原始结构的修改副本,并且原始结构未修改。

我假设以某种方式*这是在复制,但我不明白为什么/如何。 这与结构有关吗? 是函数声明中的常量吗? 幕后还有其他魔法吗?

我的理解是,"这个"是一个指针。 我曾想过当你*一个指针时,它只是取消了对那个指针的引用?? (所以我希望n指向与原始内存相同的块,但显然没有,所以我的直觉很无聊)

如果您愿意,请随时指出我的方式的错误,请详细说明。 没关系,我足够聪明,可以对引擎盖下发生的事情进行详细的技术讨论,我保证!

不,这是来自黎明之前的魔法(一个薄薄的纳尼亚参考)。它可以追溯到C语言。

由于this只是指向当前对象的指针,因此*this是对象本身,以及以下行:

N n = *this;

只是复制所述对象。然后,它修改该副本并将其返回。

如果需要指向同一对象的指针的副本,则为:

N *n = this;

它与以下内容没有什么不同:

int xyzzy = 7;           // xyzzy holds 7.
int *pXyzzy = &xyzzy;    // the address of xyzzy.
int plugh = *pXyzzy;     // a *different* address, also holding 7.
int *pTwisty = pXyzzy;   // copy *address*, pXyzzy/pTwisty both point to xyzzy.

*this本身不会创建任何副本,它只是使将由N n = ...调用的复制构造函数的类型正确。

N n = *this;

称为复制初始化。它通常会创建一个副本。

它通过尝试将*this转换为类型为N的对象来构造隐式转换序列,然后可以将该对象复制到要初始化的对象中,从而导致对复制构造函数的调用。

this的类型是"指向 N 的指针",所以应用于this的取消引用运算符 **this是一个N。表达式*this中未执行复制。它只是提供对this所指向的对象的引用。

剩下的就是副本初始化,类似于

N n1;
N n2 = n1; // initialize n2 copying the value of n1

你是对的,"这个"是一个指针。"this"是指向您所在对象的实例的指针,如果这有意义的话。

我相信问题是"N n = *this"行。

您取消引用了指针并调用了复制构造函数。这是创建副本的行。

我相信您正在寻找的是更多类似的东西:

N * N::someMethod() {
this->modify();
return this;
}

->运算符与写入"(*this)"相同。

请注意,我将该方法更改为返回指针,否则当您将此函数的返回值分配给其他内容时,您可能最终会再次调用复制构造函数。

此外,除非 modify 也是一个 const 方法(鉴于名称,这似乎不太可能),否则您不应该能够将 someMethod 编写为 const 方法。(不能在 const 方法中更改对象的逻辑内容。

即使存在符号=,工作也由复制构造函数完成。

以下代码显示了其执行的一些回显:

#include <iostream>
class N {
public:
N(){}
N( const N & n ) {
std::cout << "N( const N & n )" << std::endl;
}
N& operator = ( const N & n ) {
std::cout << "N& operator = ( const N & n )" << std::endl;
return *this;
}
N modify() const {
std::cout << "modify|entry" << std::endl;
N n2 = *this;
std::cout << "modify|exit" << std::endl;
return n2;
}
};
int main() {
N n1;
n1.modify();
}

使用此输出:

modify|entry
N( const N & n )
modify|exit
N( const N & n )