🐸 青蛙编程网
首页 / C++ / C++ 基础 / 5. 函数

函数:定义、参数与返回值

这是什么:函数 = 给一段逻辑起个名字、打个包,以后随取随用。

为什么用:代码一多就该学会"打包"——把一段功能装进函数,随取随用。C++ 的函数比 Python 多了点仪式感,但每个仪式都有用处:编译器从上往下读,函数用之前得先"报名"。

如何用:先写一个 add 函数体验"先声明、后定义",再试试同名不同参的重载(overload),最后看参数为什么默认只能拿到复印件。

声明与定义:先报名,后干活

C++ 编译器从上往下读文件,函数在被用到之前,得让它"认识"这个函数:

#include <iostream>

int add(int a, int b);   // 声明:告诉编译器"有这么个函数"

int main() {
    std::cout << add(3, 4) << std::endl;
    return 0;
}

int add(int a, int b) {  // 定义:真正的实现
    return a + b;
}

你会看到

7
组成 例子 含义
返回类型 int 函数交回来的数据类型
函数名 add 调用时喊的名字
参数列表 (int a, int b) 进厂原料,每个参数都要标类型
return return a + b; 把结果交回去,类型必须和返回类型一致

自己练手时,把函数定义直接写在 main 上面、省掉声明也完全可以;声明和定义分开写是多文件工程里的标准姿势,先混个脸熟。

参数是"传值":改了也白改

#include <iostream>

void tryChange(int x) {  // void = 不返回任何东西
    x = 100;             // 只改了自己手里那份"复印件"
}

int main() {
    int a = 1;
    tryChange(a);
    std::cout << a << std::endl;
    return 0;
}

你会看到

1

C++ 默认传值:函数收到的是原件的复印件,怎么改都烧不到外面的 a。(想让函数真改外面的值?下一章的"引用"就是干这个的。)void 表示"什么都不交回来",相当于 Python 函数不写 return。

函数重载:同名不同参(C++ 特色)

Python 里定义两个同名函数,后者会覆盖前者;C++ 却允许同名函数共存——只要参数不一样:

#include <iostream>

int area(int w, int h) {     // 两个 int:算矩形
    return w * h;
}

double area(double r) {      // 一个 double:算圆
    return 3.14 * r * r;
}

int main() {
    std::cout << area(3, 4) << std::endl;
    std::cout << area(2.0) << std::endl;
    return 0;
}

你会看到

12
12.56

编译器看你传的参数类型和个数,自动帮你挑对的那一个函数——这叫重载(overload)。

注意:仅凭返回类型不同不能构成重载。下面这段是错误的:

int area(int w, int h);   // 返回 int
double area(int w, int h); // 返回 double,参数一样,不构成重载,编译报错

常用标准库函数预习

C++ 标准库自带很多好用函数,后面章节会反复用到:

功能 函数 头文件 例子
绝对值 std::abs() <cstdlib> / <cmath> std::abs(-5) 得 5
幂运算 std::pow() <cmath> std::pow(2, 3) 得 8
平方根 std::sqrt() <cmath> std::sqrt(16) 得 4
最大/最小 std::max() / std::min() <algorithm> std::max(3, 7) 得 7
交换 std::swap() <utility> / <algorithm> std::swap(a, b)

❓ 常见问题

Q1:函数定义一定要写在 main 下面吗?

不一定。如果定义写在 main 上面,就不需要单独声明;如果写在下面,必须先声明,否则编译器在 main 里看到 add(3,4) 时"不认识"这个函数,会报错。

Q2:void 函数能用 return 吗?

可以,但只能单独写 return; 用来提前结束函数,不能带返回值(如 return 5; 在 void 函数里会报错)。

Q3:参数可以省略类型吗?

不行。C++ 的每个函数参数都必须显式标类型,如 int a, int b,不能像 Python 那样只写 a, b。

⚠️ 新手翻车现场

翻车一:在 main 下面定义函数,却忘了前面声明

// 错误:main 里调用了 add,但 add 的定义在 main 下面,编译器不认识
int main() {
    std::cout << add(3, 4);
    return 0;
}

int add(int a, int b) {
    return a + b;
}

问题:编译器从上往下读,看到 add(3,4) 时还没读到 add 的定义,报错"'add' was not declared in this scope"。

修正:在 main 上面加一行声明 int add(int a, int b);,或者把 add 的完整定义挪到 main 上面。

翻车二:函数声明和定义的参数类型不一致

int add(int a, int b);    // 声明:两个 int
double add(int a, int b); // 定义:返回 double,参数一样,不构成重载,冲突

问题:参数列表完全一样,只返回类型不同,编译器视为重复定义,报错。

修正:要么让参数不同(构成合法重载),要么让返回类型也一致。

🎯 什么时候用函数

  • 一段代码要被用两次及以上
  • 需要给代码起个有意义的名字,让主程序更易读
  • 想把复杂逻辑拆成小块,逐个测试

📝 本章小结

  • 函数由:返回类型、函数名、参数列表(每个都要标类型)、函数体组成
  • C++ 编译器从上往下读,用到函数前要先声明(或先定义)
  • 默认传值:函数收到原件的复印件,改不了外面的变量
  • 函数重载:同名不同参可共存,编译器按参数类型和个数挑选
  • void 表示不返回任何东西
  • 记忆口诀:返回类型打头阵,参数个个标类型;传值是复印件,重载看参数。

动手改

  1. 写 double celsiusToFahrenheit(double c),把 37 度转成华氏度(公式 c * 9 / 5 + 32),验证结果是 98.6
  2. 写 void sayHi(std::string name),打印"你好,××"(记得在文件头加 #include <string>)
  3. 给 area 再加一个重载:int area(int side),算正方形面积
  4. 写一个函数 int maxOfThree(int a, int b, int c),返回三个数中的最大值

下一章:指针与引用,正面硬刚 C++ 的灵魂难关 🐸

📥 下载本章代码

ZIP 内含本章全部代码文件与说明,解压即用,与教程内容同步生成。