函数
1. 函数
函数是 C++ 程序中用于封装可执行逻辑的基本单元,将一段完成特定功能的代码组织为可复用的整体。定义函数的语法如下:
返回值类型 函数名(参数类型1 参数1, 参数类型2 参数2, ...)
{
// 函数体,执行具体的逻辑
return 返回值;
}
注:
对于返回值类型为void的函数,可以不写return语句,或直接写return;提前终止。
1.1 函数的声明与定义
函数的声明和定义是两个不同的概念,遵循单一定义规则(ODR):一个程序中函数只能有一次定义,但可以有多次声明。
- 函数声明:也叫函数原型,仅告诉编译器函数的名称、返回类型和参数列表,不包含函数体。
- 函数定义:包含完整的函数体,是函数的具体实现。
int add(int a, int b); // 函数声明
int main()
{
int res = add(10, 2); // 在声明后即可调用函数
return 0;
}
int add(int a, int b) // 函数定义
{
return a + b;
}
1.2 尾置返回类型
C++11引入,可以将返回类型写在参数列表后,用auto占位,->后接真实的返回类型,往往在一些返回类型很复杂的场景中会用到:
auto add(int a, int b) -> int
{
return a + b;
}
auto get_func() -> int(*)(int, int)
{
return add;
}
1.3 数组作为函数参数
数组在作为函数参数的时候,会退化为指向首元素的指针,丢失数组长度的信息,以下三种写法完全等价:
void func(int arr[]);
void func(int arr[10]); // 这里的10没有实际约束意义
void func(int* arr);
如果要保留数组的长度,可以采取以下两种写法:
void func(int* arr, int n); // 额外传入一个参数当数组的长度
void func(int (&arr)[10]); // 直接传入数组的引用
多维数组作为参数的时候,第一维会退化为指针,而其余维度必须明确指定:
void func(int arr[][3]);
void func(int (*arr)[3]);
2. 默认参数
可以在函数声明中指定形参为某个默认值,调用时可以不传入对应实参,自动使用默认值。
#include <iostream>
int calc(int a, int b, int k = 3)
{
return (a + b) * k;
}
int main()
{
std::cout << calc(1, 2) << std::endl;
std::cout << calc(1, 2, 3) << std::endl;
}
函数默认参数有以下要求:
1. 默认参数必须放在最右侧,不允许跳过某个参数为左边参数设置默认值
// 错误写法
void func(int a, int b = 3, int c, int d = 20);
2. 如果函数的声明与定义分开,只在声明中指定默认值
// 声明
void print(int a, int b = 10, int c = 20);
// 定义
void print(int a, int b, int c)
{
std::cout << a << " " << b << " " << c << std::endl;
}
// 调用
print(1); // 输出 1 10 20
print(1, 2); // 输出 1 2 20
print(1, 2, 3); // 输出 1 2 3
3. 函数重载
函数重载是指在同一作用域内,用同一个函数名定义多个功能相似但参数不同的函数,由编译器在编译阶段根据调用的实参自动匹配对应版本。
- 作用域相同
- 函数名完全一致
- 参数列表不同:
- 参数的个数不同
- 参数的类型不同
- 参数类型的排列顺序不同
int func(int x, int y);
double func(double x, double y);
3.1 注意事项
1. 返回值的类型并不参与函数的重载
下面例子不构成函数重载,而是同一个函数的重定义:
int func(int x);
int func(int y);
2. 顶层const不构成重载,底层const则构成
- 顶层
const:修饰变量本身的值不可变,对编译器而言是同一种参数: - 底层
const:修饰指针/引用指向的内容,语义上有区别
// 错误操作:顶层 const 不构成重载,因而出现重复定义错误
void func(int a);
void func(const int a);
// 正确操作:底层 const 构成重载
void func(int* p);
void func(const int* p);
3. 默认参数可能会引发二义性,致使重载失败
void test();
void test(int x = 10);
test(); // 调用函数时可以同时匹配两个函数,编译器会进行报错
3.2 底层实现
TODO


