我理解与任何其他变量一样,参数的类型决定了参数与其参数之间的交互。我的问题是,为什么你会引用一个参数vs为什么你不参考?为什么有些函数参数引用而有些参数没有?难以理解这样做的好处,有人可以解释一下吗?
答案 0 :(得分:48)
通过引用传递的能力存在有两个原因:
修改参数的示例
void get5and6(int *f, int *s) // using pointers
{
*f = 5;
*s = 6;
}
这可以用作:
int f = 0, s = 0;
get5and6(&f,&s); // f & s will now be 5 & 6
OR
void get5and6(int &f, int &s) // using references
{
f = 5;
s = 6;
}
这可以用作:
int f = 0, s = 0;
get5and6(f,s); // f & s will now be 5 & 6
当我们通过引用传递时,我们传递变量的地址。通过引用传递类似于传递指针 - 在这两种情况下只传递地址。
例如:
void SaveGame(GameState& gameState)
{
gameState.update();
gameState.saveToFile("save.sav");
}
GameState gs;
SaveGame(gs)
OR
void SaveGame(GameState* gameState)
{
gameState->update();
gameState->saveToFile("save.sav");
}
GameState gs;
SaveGame(&gs);
<小时/> 由于只传递了地址,因此变量的值(对于大型对象来说可能非常大)不需要复制。因此,通过引用传递可以提高性能,尤其是在以下情况下:
另外,请阅读const
个参考文献。使用时,无法在函数中修改参数。
答案 1 :(得分:22)
请忘记现在的指针。拿出一粒盐。
引用是对象。当您通过引用传递时,您传递 对象。
当您通过值传递时,您传递对象的副本; 另一个对象。它可能具有相同的状态,但它是不同的实例;克隆。
因此,如果您:
通过引用可能是有意义的const
参考。如果您:
,通过价值可能是有意义的int
,除非我想修改它。)在这里,看看这段代码:
#include<iostream>
struct Foo {
Foo() { }
void describe() const {
std::cout<<"Foo at address "<<this<<std::endl;
}
};
void byvalue(Foo foo) {
std::cout<<"called byvalue"<<std::endl;
foo.describe();
}
void byreference(Foo& foo) {
std::cout<<"called byreference"<<std::endl;
foo.describe();
}
int main() {
Foo foo;
std::cout<<"Original Foo"<<std::endl;
foo.describe();
byreference(foo);
byvalue(foo);
}
并按照以下方式编译:{{1}}
运行它:g++ example.cpp
并检查输出(计算机中的实际地址可能有所不同,但这一点仍然存在):
./a.out
请注意Original Foo
Foo at address 0x7fff65f77a0f
called byreference
Foo at address 0x7fff65f77a0f
called byvalue
Foo at address 0x7fff65f779f0
地址与called byreference
地址的相同方式(均为Original Foo
)。并注意0x7fff65f77a0f
地址不同(called byvalue
)的方式。
把它提升一个档次。将代码修改为如下所示:
0x7fff65f779f0
以相同的方式编译它,并注意输出(注释不在输出中;为清晰起见包括在内):
#include<iostream>
#include<unistd.h> // for sleeping
struct Foo {
Foo() { }
Foo(const Foo&) {
sleep(10); // assume that building from a copy takes TEN seconds!
}
void describe() const {
std::cout<<"Foo at address "<<this<<std::endl;
}
};
void byvalue(Foo foo) {
std::cout<<"called byvalue"<<std::endl;
foo.describe();
}
void byreference(Foo& foo) {
std::cout<<"called byreference"<<std::endl;
foo.describe();
}
int main() {
Foo foo;
std::cout<<"Original Foo"<<std::endl;
foo.describe();
byreference(foo);
byvalue(foo);
}
因此,该代码旨在夸大副本的成本:当您通过引用进行调用时,不会产生此成本。当你按价值打电话时,你必须等待十秒钟。
注意:我的代码是使用GCC 4.8.1在OS X 10.7.4中编译的。如果您在Windows中,可能需要与Original Foo
Foo at address 0x7fff64d64a0e
called byreference
Foo at address 0x7fff64d64a0e # this point is reached "immediately"
called byvalue # this point is reached TEN SECONDS later
Foo at address 0x7fff64d64a0f
不同的内容才能使unitsd.h
来电。
也许这有帮助。
答案 2 :(得分:1)
使用传递参考的优点: 您不必创建只传递内存指针的数据副本。 (巨大的表现胜利认为如果你有一个巨大的物体,你传过来)。 您可以“返回”多个值我知道c / c ++中的某些函数返回一个数字,其中一个参数是指向被操纵的数据的指针。
使用传递引用的缺点: 您必须小心修改传递的数据,因为它可能会导致您可能想要或可能不想要的副作用。
答案 3 :(得分:1)
通过引用同样是通过指针手动传递变量,但是通过引用不会让用户处理“容易搞乱”的指针。