这是什么奇怪的魔法?
What strange magic is *this?
快速问题。 我想了解*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 )
- 为不同配置设置MSVC_RUNTIME_LIBRARY的正确方法是什么
- C++避免重复声明的语法是什么
- 在C++中,将大的无符号浮点数四舍五入为整数的最佳方法是什么
- 实现无开销push_back的最佳方法是什么
- C++从另一个类访问公共静态向量的正确方法是什么
- "throw expression code" 1e7 >返回 d 是什么?投掷标准::overflow_error( "too big" ) : d;意味 着?
- C++中名称篡改的目的是什么
- 在 c++ 中拥有一组结构的正确方法是什么?
- 这个指针和内存代码打印是什么?我不知道是打印垃圾还是如何打印我需要的值
- 是什么阻止DOMTimerCoordinator::NextID进入无休止的循环
- 派生类销毁的最佳实践是什么
- 这个语法std::class<>{}(arg1, arg2) 在C++中是什么意思?
- 通过JNI传递数据数组的最快方法是什么
- "using namespace std;"在C++的作用是什么?
- 在两台机器之间进行时间戳的最佳c++chrono函数是什么
- 文件系统:复制功能的速度秘诀是什么
- 用常见虚拟函数实现的任意组合来实现派生类的正确方法是什么
- 使用QQuickFramebufferObject时同步数据的最佳方式是什么
- 是什么原因导致它无法编译?它是声明签名还是在函数本身的实现中
- 使用不同的CRT将新的C++代码与旧的(二进制)组件隔离开来的最佳方法是什么