- 按值传递
- 按引用传递
- 按地址传递
通过引用传递和通过值传递的区别非常重要。当您通过值传递时,实际上是传递了一个问题值的副本。无论函数中发生什么情况,在调用者中的值都将保持不变。因此,假设您有一个将一个int
加一并返回一个int
的函数:
int addOne(int theNumber)
{
theNumber += 1;
return theNumber;
}
在这里,你是按值传递的。你需要像这样调用它:
int a = 10;
int b = addOne(a); // b gets 11, but a remains the same
int addOne(int &theNumber)
{
theNumber += 1;
return theNumber;
}
请注意,函数体保持不变。同样,您可以这样调用它:
int a = 10;
int b = addOne(a); // b gets 11, but this time a is also changed to 11.
a
的隐式指针,但您可以将其视为传递a
本身。由于您传递的是a
而不是a
的值的副本,因此函数实际上会更改a
本身。int addOne(int *theNumber)
{
*theNumber = *theNumber + 1;
return *theNumber;
}
这与参考版本执行的相同操作,但指针在此处是显式的。您可以像以下方式使用它:
int a = 10;
int b = addOne(&a); // b gets 11, but this time a is also changed to 11.
所以,在这种情况下,您明确传递了a
的地址,也就是指向a
的指针。如果您只习惯按值传递,则应该很熟悉。这就是在C和一些其他类C语言中通过引用传递a
的方式。它可以正常工作,但您必须自己处理所有指针内容。C++将“按引用传递”的概念添加到语言中,以使所有这些更加容易。
最后一种可能性是传递一个const引用,它避免了复制值,但禁止在被调用函数中更改它。如果一个函数采用const引用,则可以将其解释为不更改参数的承诺(并且编译器会强制执行该承诺)。如果值大于几个字节,则特别有用,因此如果可以避免复制该值,则通常将对象按const引用传递。
因此,作为指导方针,当您不希望调用者传递的内容发生更改时,请按值或const引用传递。当您想要更改时,请按引用传递。除非涉及需要它的C库或其他代码,否则不要传递指针。
按值传递参数会复制该参数,该副本将在函数内部使用。参数的修改将在函数结束后丢失:
例如:
void f(int a);
[
a = 25;
}
int main()
{
int i = 10;
f(i);
cout<<i; //the printed value will be 10;
}
但如果您使用地址或引用,那就不同了:
void g(int &a)
{
a = 25;
}
int main()
{
int i = 10;
g(i);
cout<<i; // the printed value is 25
}
当你传递自己定义的对象或其他库中的对象时,情况会变得更加混乱/复杂。一个限制依赖关系的问题是你可以前向声明一个类而不实际包含头文件,例如:
// #include "myclass.h" // we **Don't** include it! Less code-bloat
class MyClass; // foward-declare it
void MyFunction( MyClass* obj );
// good to go, define this in .cpp file.
// someone including **This** header won't have to include myclass.h
void MyFunction( MyClass& obj ); // Not Legal!
void MyFunction( MyClass obj ); // Not Legal!
void MyFunction( const MyClass& obj ); // Not Legal!
我尝试使用“const MyClass& obj”约定,但有时由于库阻止了这种模式而不可能。如果你刚开始学习,请尝试通过值传递像'int','double'这样的东西,并且不要担心它。将不应更改的标准模板对象作为“const std::Class& var”传递,并让函数返回东西而不是通过引用修改。
当你的代码实现所需功能并担心性能问题,或者你使用的库需要它时,请重新考虑方法。