我所知道的事实:
我的问题:
将变量名作为参数传递和传递引用有什么区别?例如,
void func(int a); vs void func2(int& b);
万分感谢!
答案 0 :(得分:6)
以下是了解差异的方法:
现在,在某些情况下,引用可能会被实现为指针,但从语言的角度来看,引用只不是指针,它们实际上是已存在对象的附加名称。
由于指针是对象,并且具有状态,因此将指针传递给函数将复制该状态,指针的状态,而不是指针的状态。但是,引用没有状态,因此如果传递对函数的引用,则它是您传递的引用对象(通过复制)。
通过观察,变量名称和引用的使用是 更换。这是真的吗?
“引用是昵称”是理解参考文献的最佳方式。
将变量名称作为参数传递有什么区别 并传递参考?如,
void func(int a); vs void func2(int& b);
第一个实现请求传递的对象的副本。也就是说,内部func()可以对a执行任何操作,而无需更改传递给func()的对象,因为内部func()创建了该对象的副本并操纵副本,而不是原始副本。
第二个实现要求“已存在的对象的昵称”。首先,对象必须存在,如果传递,将在函数内创建它的昵称。该昵称,即引用b
,仍然是原始对象的昵称。这意味着对b
执行的任何操作都将影响传递给func2()的原始对象。
奖金阶段:
此时,如果您还不知道const
,那可能会有用:在函数签名const
中使用引用来指定“只读”的参数。
让我澄清一下:
void func3( const int& b);
这里func3说:“我需要访问一个对象,但实际上我不会复制它。但我保证不会更改该对象。”
那么,为什么我们需要呢?因为某些对象复制起来很昂贵。 int复制很便宜,所以大多数人只会传递它,而func()和func3()基本上是等价的(取决于实现但通常是真的)。
但是,如果我们想传递一个非常大的对象,比如数据缓冲区,我们真的不想再次复制它只是为了应用一些算法。
所以我们确实希望通过引用传递它。但是,根据功能的不同,有时您需要提取信息并使用它,因此您只需要对参数进行“只读”访问。在这种情况下,您使用const Object&
。但是,如果需要将算法应用于传递的对象,则需要能够对其进行修改,您可以将其称为“写入访问”。在这种情况下,您需要使用普通参考。
要求复制基本上意味着你想要操作一个与传递的对象状态相同的对象,但不是传递的对象。
总结:
func( T object )
:我想要一个类型为T的对象的副本; func( T& object )
:我希望对类型为T的对象进行“写访问” - 假设我将修改该对象!; func( const T& object ) or func( T const & object ) // which are the same
:我想阅读一个对象的状态,但我向你保证我不会修改它,我想要“只读”访问。实际上,使用const_cast<>
可以违反“只读”保证,但这是一个不同的故事,它仅用于一些非常非常狭窄的情况。
您需要知道的最后一件事是,如果您有成员函数,那么您可以这样做:
class K{
public:
void func() const; // see the const?
};
在这个特定情况下,你说的是函数内部,它基本上等同于: void func(const K * this);
在这种情况下,您可以看到这是一个指针,但它指向一个const对象。这意味着func()保证它所属的对象(this)永远不会通过此函数进行修改(除了一些特定情况,请参阅mutable
关键字,另一个长篇故事)。
答案 1 :(得分:3)
假设你有这两个功能:
void addone(int a) {
a += 1;
}
void addone_bis(int &a) {
a += 1;
}
如果您在main
函数中调用第一个函数,则该值仅在函数addone
中更改,而不在主函数中更改,而如果您调用addone_bis
的值,则也将在main
函数中更改。
int main() {
int test_a = 10;
int test_b = 11;
addone(test_a);
// test_a still equals 10.
addone_bis(test_b);
// test_b now equals 12.
}
我是否正确回答了您的问题?
答案 2 :(得分:0)
您的第一个例子是所谓的PASSING BY VALUE。这意味着ACTUAL值的副本被传递到例程中。
当传递你的第二个例子的方式时,这就是所谓的通过参考传递。引用通常是将变量传递给例程,这样它的ACTUAL VALUE可以被调用的例程修改而不需要DE-REFERENCING。