函数原型
自订函数的定义需要放在main()或呼叫之前,如果放在main()或呼叫之后,例如
#include <iostream> int main() { do_something("What's truth?"); do_something("There is no spoon."); return 0; } void do_something(char* s) { std::cout << s << std::endl; }
这样无法通过编译
$ g++ u0801_1.cpp u0801_1.cpp:4:5:错误:使用未声明的标识符“do_something” do_something(“真相是什么?”) ^ u0801_1.cpp:5:5:错误:使用未声明的标识符“do_something” do_something("没有勺子。"); ^ 产生了2个错误。 $
因为C++ 预设任何识别字使用前都得先定义或宣告,如果我们要把自订函数的定义放在main()或呼叫之后,就要先宣告函数原型(function prototype) ,因此上例要改写如下
#include <iostream> void do_something(char*); int main() { do_something("What's truth?"); do_something("There is no spoon."); return 0; } void do_something(char* s) { std::cout << s << std::endl; }
函数原型的宣告在第3 行
void do_something(char*);
参数列方面宣告参数的型态即可,编译执行结果如下
$ g++ u0801_2.cpp $./a.out 复制代码 什麼是真實呢? 没有勺子。 $
通常函数原型的宣告会放在标头档(header file) 之中,函数实作则会放在其他程式档案。
指标参数
如果有需要用函数直接修改某些变数(variable) ,就可以用该变数的指标(pointer) 当参数,例如
#include <iostream> void do_something(int* n_ptr) { *n_ptr = 10; } int main() { int a = 22; std::cout << a << std::endl; do_something(&a); std::cout << a << std::endl; return 0; }
do_something()接受一个整数指标参数,然后将参数重新设定为10
void do_something(int* n_ptr) { *n_ptr = 10; }
编译执行,结果如下
$ g++ u0802_1.cpp $./a.out 复制代码 22 10 $
由于函数只能有一个回传值,因此当程式中有多个变数需要用函数修改时,利用指标当参数为一个解决方案,另举一例如下
#include <iostream> int do_something2(int* n1_ptr, int* n2_ptr) { *n1_ptr *= 2; *n2_ptr *= 2; return *n1_ptr + *n2_ptr; } int main() { int a = 22; int b = 33; std::cout << "a + b: " << do_something2(&a, &b) << std::endl; std::cout << "a: " << a << std::endl; std::cout << "b: " << b << std::endl; return 0; }
$ g++ u0802_2.cpp $./a.out 复制代码 a+b:110 答:44 乙:66 $
参考参数
如果有需要用函数直接修改某些变数,就可以设计接收参考参数(reference parameter) 的函数,例如
#include <iostream> void do_something(int& n_ref) { n_ref = 10; } int main() { int a = 22; std::cout << a << std::endl; do_something(a); std::cout << a << std::endl; return 0; }
do_something()接受一个整数参考参数,然后将参数重新设定为10
void do_something(int& n_ref) { n_ref = 10; }
编译执行,结果如下
$ g++ u0803_1.cpp $./a.out 复制代码 22 10 $
由于函数只能有一个回传值,因此当程式中有多个变数需要用函数修改时,利用参考当参数为一个解决方案,另举一例如下
#include <iostream> int do_something2(int &n1_ref, int &n2_ref) { n1_ref *= 2; n2_ref *= 2; return n1_ref + n2_ref; } int main() { int a = 22; int b = 33; std::cout << "a + b: " << do_something2(a, b) << std::endl; std::cout << "a: " << a << std::endl; std::cout << "b: " << b << std::endl; return 0; }
编译执行,结果如下
$ g++ u0803_2.cpp $./a.out 复制代码 a+b:110 答:44 乙:66 $
预设参数
函数可以有预设参数(default parameter) ,也就是替参数设定预设值,例如
#include <iostream> void do_something(int n = 22) { std::cout << n << std::endl; } int main() { do_something(11); do_something(); do_something(); return 0; }
替参数n设定预设值,就是直接在参数列指派数值
void do_something(int n = 22) {
这样不使用参数也可以呼叫
do_something(11); do_something(); do_something();
编译执行,结果如下
$ g++ u0804_1.cpp $./a.out 复制代码 11 22 22 $
预设参数可以是选择性的,也就是可以替特定参数设定预设值,其他参数则须呼叫时填入小括弧,需要注意这样的预设参数必须放在参数列的后面,例如
#include <iostream> void do_something2(int n1, int n2 = 5, int n3 = 0) { std::cout << n1 + n2 + n3 << std::endl; } int main() { do_something2(6); do_something2(6, 9); do_something2(3, 4, 5); return 0; }
留意n1并没有预设值
void do_something2(int n1, int n2 = 5, int n3 = 0) { std::cout << n1 + n2 + n3 << std::endl; }
因此呼叫时至少要有一个参数
do_something2(6); do_something2(6, 9); do_something2(3, 4, 5);
编译执行,结果如下
$ g++ u0804_2.cpp $./a.out 复制代码 11 15 12 $
此外要注意参数列的顺序,预设参数只能放在参数列的后面,像是下面就无法通过编译
void do_something2(int n1 = 6, int n2, int n3 = 0) {
可变参数
函数的参数数量也可以不固定,这是在参数列里利用...构成可变参数(variadic arguments) ,举例如下
#include <iostream> #include <cstdarg> int sum(int n_args, ...) { va_list ap; va_start(ap, n_args); int sum = va_arg(ap, int); for (int i = 2; i <= n_args; i++) { sum += va_arg(ap, int); } va_end(ap); return sum; } int main() { std::cout << sum(3, 11, 22, 33) << std::endl; std::cout << sum(3, 19, 20, 21) << std::endl; std::cout << sum(3, 3, 65, 101) << std::endl; return 0; }
此例的sum()用来计算参数的总和,除了第一个参数n_args为计算总和的数量之外,其他的参数都会被累加起来,结果回传为整数
int sum(int n_args, ...) { va_list ap; va_start(ap, n_args); int sum = va_arg(ap, int); for (int i = 2; i <= n_args; i++) { sum += va_arg(ap, int); } va_end(ap); return sum; }
编译执行,结果如下
$ g++ u0805.cpp $./a.out 复制代码 66 60 169 $