我一直认为引用在功能上与指针相同,它们只是有更友好的语法,以及其他一些细微的差异(引用不能被分配null,它们不能被重新分配)。
但是今天我看到这段代码,我不明白为什么它是正确的:
有一个简单的结构,
Color3B
。我们像这样在堆栈上创建一个:
Color3B color(255, 0, 0);
还有另一个类,它的实例变量之一是
Color3B
类型。
class Node{
private:
Color3B _color;
public:
void setColor(const Color3B& color){
_color = color;
}
};
用途:
void someFunction(){
Color3B color(255, 0, 0);
_someNode->setColor(color);
}
我认为当
color
超出范围时:当someFunction
结束时,它就会被销毁。但是 setColor
获取在堆栈上创建的内容的内存地址,并将其存储。但是没有问题,当我访问 Node
的 _color
时,它始终存在并且具有正确的值。
我在这里缺少什么?
_color = color;
采用 color
的值副本,因此 color
最终超出范围并不重要。
如果成员变量
_color
是 本身 引用,则会遇到问题。
void someFunction(){
Color3B color(255,0,0); // (1)
_someNode->setColor(color);// (2)
} // (5)
void setColor(const Color3B& color){ // (2)(3)
_color = color; // (4)
}
让我们看看这里会发生什么:
color
setColor
color
现在是 color
color
的值复制到 _color
(赋值),因为 _color
不是引用color
被摧毁如果
_color
是参考,就会发生您认为应该发生的错误。
class Node{
private:
const Color3B& _color;
public:
void setColor(const Color3B& color){
_color = color;
}
};
这段代码会产生您期望的错误。现在,您实际上会将堆栈上颜色的地址保存到
Node
中,并且该地址将在 someFunction()
末尾被销毁。然而你不这样做。您的 Node
有自己的 Color3B
对象,而不是对其的引用。因此,代码 _color = color
实际上执行从 someFunction()
中的颜色到 Node
对象中的颜色的复制。现在,即使原来的颜色被破坏了,Node
中的颜色仍然存在。
如果您用指针编写
setColor()
,则相当于您的代码:
void setColor(const Color3B* color){
_color = *color;
}
因为引用不是变量的地址而是别名。所以上面代码中的
color
(如果是引用的话)代表的是它的值,而不是地址。要获取地址,您必须写 &color
。