函数

rand 函数

函数原型: int rand(void); 所需头文件: <cstdlib> 函数及返回值: 生成并返回一个伪随机数


srand 函数

函数原型: void srand(unsigned int seed); 参数: 生成随机数的种子 所需头文件: <cstdlib> 函数: 设置 rand() 生成一系列伪随机整数的起始点。使用 1 作为种子参数可以重新初始化 rand()。


需要注意的是,如果不使用种子,每次程序运行生成的随机数将是 固定且不变 的。因此,rand 函数返回的是 伪随机数

引用的概念

  • 引用 (&) 是标识符的别名;
  • 定义引用时,必须同时初始化以指向现有对象。 例如:
1
2
3
4
int i, j;
int &ri = i; // 定义 int 引用 ri,并将其初始化为变量 i 的引用
j = 10;
ri = j; // 等价于 i = j;
  • 一旦引用被初始化,就不能更改为指向其他对象。 引用可以作为形式参数使用。

引用可以实现函数形式参数与实际参数之间的双向传递

例如,以下程序:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include<iostream>
using namespace std;

void swap(int& a, int& b) // 定义引用类型的形式参数
{
int t = a;
a = b;
b = t;
}

int main() {
int x = 5, y = 10;
cout<<"x = "<<x<<" y = "<<y<<endl;
swap(x, y);
cout<<"x = "<<x<<" y = "<<y<< endl;
return 0;
}

可变参数的函数

C++ 标准主要提供两种方法

  • 如果所有实际参数类型相同,可以传递一个称为 initializer_list 的标准库类型;
  • 如果实际参数类型不同,我们可以编写可变参数模板(第 9 章)。

    initializer_list

initializer_list 是一个标准库类型,用于表示特定类型的值数组,在同名的头文件中定义。


initializer_list 的使用

  • initializer_list 是一个类模板(模板在第 9 章中详细介绍)
  • 使用模板时,需要在模板名称后跟一对尖括号,尖括号内为类型参数。例如:
1
2
initializer_list<string>  ls;  // initializer_list 的元素类型为 string
initializer_list<int> li; // initializer_list 的元素类型为 int
  • 关于 initializer_list 的一个特殊点是,其对象中的元素始终是常量值,我们不能更改 initializer_list 对象中元素的值。
  • 带有 initializer_list 形式参数的函数也可以同时具有其他形式参数。

    使用 initializer_list 的示例

  • 在编写代码以输出程序生成的错误消息时,最好使用统一的函数来实现此功能,以便对所有错误的处理可以保持一致。然而,错误消息的类型是不同的,调用错误消息输出函数时传递的参数也会有所不同。
  • 使用 initializer_list 编写一个可以处理可变数量形式参数的错误消息输出函数。

    内联函数

  • 声明时使用关键字 inline。
  • 在编译时,将调用位置替换为函数体,从而节省参数传递、控制转移等的开销。
  • 注意:
    • 内联函数体不能有循环语句和 switch 语句;
    • 内联函数的定义必须出现在第一次调用内联函数之前;
    • 内联函数不能声明异常接口。

      应用示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <iostream>

using namespace std;

const double PI = 3.14159265358979;

inline double calArea(double radius) // inline 关键字
{

return PI * radius * radius;

}

int main()
{

double r = 3.0;

double area = calArea(r);

cout << area << endl;

return 0;

}

本质上,它省略了函数调用和返回,类似于将函数体直接粘贴到调用位置。

### constexpr 函数(用法不太清楚)
#### constexpr 函数示例
- constexpr int get_size() { return 20; } - constexpr int foo = get_size(); // 正确:foo 是一个常量表达式

带默认参数值的函数

默认参数值声明的顺序

  • 带默认值的形式参数必须列在参数列表的最右侧,即不能有没有默认值的参数在默认参数值的右侧;
  • 调用时实际参数与形式参数的绑定顺序是从左到右。
  • 示例:

1
2
3
int add(int x, int y = 5, int z = 6);// 正确
int add(int x = 1, int y = 5, int z);// 错误
int add(int x = 1, int y, int z = 6);// 错误

默认参数值与函数调用位置

如果一个函数有原型声明,并且原型声明在定义之前,则默认参数值应在函数原型声明中给出;如果只有函数定义,或者函数定义在前,则默认参数值可以在函数定义中给出。 例如:

1
2
3
4
5
6
7
8
9
int add(int x = 5 ,int y = 6)// 原型声明在前
int main()
{
add();
}
int add(int x,int y)
{
return x+y;// 这里不能再次指定默认值
}

1
2
3
4
5
6
7
8
int add(int x = 5 ,int y = 6)// 只有定义,没有原型声明
{
return x+y;
}
int main()
{
add();
}

函数重载

C++ 允许在同一作用域内使用相同的函数名声明具有相似功能的函数,从而形成重载。这方便使用且易于记忆。

注意事项:

  • 重载函数必须具有不同的形式参数:不同的数量或不同的类型。
  • 编译器将根据实际参数和形式参数的类型和数量的最佳匹配来选择调用哪个函数。(编译器不区分形式参数名称和函数返回值)
  • 不要将功能不同的函数声明为重载函数,以避免在调用结果中产生误解和混淆。

函数重载应用示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <iostream>
using namespace std;
int sumOfSquare(int a, int b) {
return a * a + b * b;
}
double sumOfSquare(double a, double b) {
return a * a + b * b;
}
int main() {
int m, n;
cout << "输入两个整数: ";
cin >> m >> n;
cout<<"它们的平方和: "<<sumOfSquare(m, n)<<endl;
double x, y;
cout << "输入两个实数: ";
cin >> x >> y;
cout<<"它们的平方和: "<<sumOfSquare(x, y)<<endl;
return 0;
}

运行结果: 输入两个整数: 3 5 它们的平方和: 34 输入两个实数: 2.3 5.8 它们的平方和: 38.93