函数参数 (function parameter)#
按传值、传指针、传引用来区分参数是没有意义的, 我们更应该考虑参数的实际用途: 不是去考虑我们应该怎样传参, 而是 去考虑我们要用这个参数做什么.
对于一个变量我们可以进行读取和写入, 那么对于参数也是如此:
- 输入参数 (in parameter): 通过参数为函数输入值.
函数只从实际参数中读取信息, 而不修改实际参数的信息.
1void function(int value) { 2 value = value * 5; 3 cout << value; // 输出 5 4} 5 6int main() { 7 int value = 1; 8 function(value); 9 cout << value; // 输出 1 10}
- 输出参数 (out parameter): 通过参数为函数输出值.
函数只修改实际参数的信息, 而不读取实际参数的任何信息.
1void function(int& value) { 2 value = 5; 3} 4 5int main() { 6 int value = 1; 7 function(value); 8 cout << value; // 输出 5 9}
- 输入输出参数 (in-out parameter): 通过参数为函数输入值, 并输出值.
函数既从实际参数中读取信息, 又修改实际参数的信息.
1void function(int& value) { 2 std::cout << value; // 输出 1 3 value = 5; 4} 5 6int main() { 7 int value = 1; 8 function(value); 9 cout << value; // 输出 5 10}
传参决策#

C++98 传参决策#
相关核心准则
决策由来: 常见传参方式的用途分析#
我们来分析一下见过的传参方式, 对它们的用途进行分类.
其中 parameter
表示参数列表中的形式参数, argument
表示调用时传递的实际参数.
function(int parameter)
按值传参发生拷贝,
int parameter = argument
是从实际参数拷贝得到的新对象, 因此自然不可能通过parameter
修改argument
, 是 输入参数.function(int& parameter)
按引用传参,
int& parameter = argument
是对实际参数的引用, 对parameter
的任何操作其实就是对argument
的操作, 是 输出参数 (如果只写入) 或 输入输出参数 (既读取又写入).function(int const& parameter)
按 const 引用传参,
int const& parameter = argument
是对实际参数的引用, 对parameter
的任何操作其实就是对argument
的操作, 但这个引用只能用于读取不能用于写入, 是 输入参数.function(int* parameter)
按指针传参,
int* parameter = &argument
指向实际参数, 对*parameter
的任何操作其实就是对argument
的操作, 是 输出参数 (如果只写入) 或 输入输出参数 (既读取又写入).function(int const* parameter)
按 const 指针传参,
int const* parameter = &argument
指向实际参数, 对*parameter
的任何操作其实就是对argument
的操作, 但这个解引用只能用于读取不能用于写入, 是 输入参数.
决策由来: 使用返回值而非输出参数#
输出参数方式并不直接:
1void function(int& value) {
2 value = 5;
3}
4
5/* 中间隔了几百行代码 */
6
7int main() {
8 int value = 1;
9 function(value); // 传入参数, 应该不会改变我的 value, 对、对吧?
10 std::cout << value; // 输出 5😱
11}
相比于输出参数, 我们有一个更好的输出方案——返回值:
1int function() {
2 return 5;
3}
4
5int main() {
6 int value = function();
7}
如果需要返回多个值, 使用结构体:
1struct Symmetric_minus_result {
2 int lhs_minus_rhs;
3 int rhs_minus_lhs;
4};
5
6Symmetric_minus_result symmetric_minus(int lhs, int rhs) {
7 return {lhs - rhs, rhs - lhs};
8}
传值? 传指针?#
这样以参数的实际用途来分析, 才是最反映我们编写代码的逻辑的, 也是最符合事实的: 传指针其实也是传值, 之所以区别开来教, 就是内含了用参数的实际用途来区别的想法.
以 by_value(int value)
和 by_pointer(int* pointer)
为例.
by_value(int value)
调用时, 拷贝的是 int
类型; 而 by_pointer(int* pointer)
调用时, 拷贝的是 int*
类型.
在 指针 (pointer) 中已指出, 指针是一个对象, 它存储了指向对象的地址, 自然拷贝得到的新指针也存储了那个地址. 因此自然地, 这个新指针解引用也能访问那个指向的对象:
1int temp = 5;
2
3void function(int* pointer) {
4 pointer = &temp; // pointer 指向 temp
5}
6
7int main() {
8 int value = 0;
9 int* pointer = &value; // &value 取地址, 得到指向 value 的一个指针
10
11 function(pointer); // 调用时这个指针也是传值, 发生拷贝, 只是拷贝得到的指针也指向 value
12
13 std::cout << *pointer; // 输出 0, 它依然指向 value!
14}