资料来源:南科大 余仕琪 C/C++ Program Design
LINK:
- CPP/week07 at main · ShiqiYu/CPP · GitHub
- 7.1-default-arguments_哔哩哔哩_bilibili
- 7.2-function-overloading_哔哩哔哩_bilibili
- 7.3-function-templates_哔哩哔哩_bilibili
- 7.4-function-pointers-and-references_哔哩哔哩_bilibili
0 概述
本节课为函数的进阶课程,主要内容包括:默认参数、函数重载、函数模板、递归、指向函数的指针。
1 Default Arguments 默认参数
默认参数是C++中才有的概念。需要注意的是:
- 默认参数设置时只能放在后面不能放在前面
2 Function Overloading 函数重载
函数重载同样是C++里面有的特性。它可以实现存在多个一样的函数名称
- C++内部对于函数的查找依赖于函数名称和函数参数列表,二者都相同才认定两个函数是一样的。
- 因此,相同的函数名称和函数参数列表不能有不同的输出类型,否正会造成混乱(它究竟要输出什么类型?)
- 函数在使用时要明确让编译器选择什么类型,否正会出现问题,比如声明 int sum(int x, int y)和 float sum(float x, float y),使用却输入 sum(1, 2.2),让编译器两个都可以使用而陷入选择
3 Function Templates 函数模板
为什么需要函数模板?因为在使用函数重载的过程中存在一部分相同的代码需要写,在管理上不方便。
通过使用函数模板、定义一个泛形T解决以上问题。
- 函数模板在定义后编译器编译时并不知道泛形具体是什么类型,并不会编译模板里面的内容。需要进行实例化之后才能让编译器进行编译
- 在实例化过程中,可以忽略<>
- 同时,存在隐式实例化,即程序会根据调用进行实例化。
- 对于想要实现一些特殊运算,比如泛形为结构体,要实现两个结构体之间的加法,这种操作需要进行特例化
specialization.cpp:
#include <iostream>
#include <typeinfo>
using namespace std;
template<typename T>
T sum(T x, T y)
{
cout << "The input type is " << typeid(T).name() << endl;
return x + y;
}
struct Point
{
int x;
int y;
};
// Specialization for Point + Point operation
template<> //注意必须加<>,否则就会变成实例化而不是特例化
//之前的实例化没有括号:
// Explicitly instantiate
// template double sum<double>(double, double);
Point sum<Point>(Point pt1, Point pt2)
{
cout << "The input type is " << typeid(pt1).name() << endl;
Point pt;
pt.x = pt1.x + pt2.x;
pt.y = pt1.y + pt2.y;
return pt;
}
int main()
{
//Explicit instantiated functions
cout << "sum = " << sum(1, 2) << endl;
cout << "sum = " << sum(1.1, 2.2) << endl;
Point pt1 {1, 2};
Point pt2 {2, 3};
Point pt = sum(pt1, pt2);
cout << "pt = (" << pt.x << ", " << pt.y << ")" << endl;
return 0;
}
4 Function Pointers and References 函数指针和引用
函数指针是指向函数的指针,指向的具体内容是指令区的地址。
函数指针具有以下作用:
-
调用函数:函数指针允许您通过指针调用函数。与C语言类似,您可以定义一个函数指针并将其赋值为已声明函数的地址。然后,您可以使用函数指针来调用函数,而不必直接使用函数名。
-
作为函数的参数(更常见):函数指针还可以作为函数的参数。通过规定好的指针类型,您可以在编程中使用变量来代替函数进行运算。这对于简化代码并在一定程度上节约内存非常有用。例如,当您需要返回数组中的元素时,可以返回数组的首元素地址给调用函数,从而让函数返回多个值。此外,您还可以使用指针函数来动态分配内存并返回该内存的地址,以便其他函数可以操作它。
同样的,函数也有引用。引用需要在定义时就明确对象。
5 Recursive Functions 递归函数
递归函数是指一个函数在其定义中又调用自身的过程。这种调用自身的行为称为递归。
递归函数通常由以下两个部分组成:
-
基本情况(Base Case):这是递归的终止条件。如果没有基本情况,递归函数将无限地调用自己,导致栈溢出。基本情况是一个判断,当满足某个条件时,递归不再继续,而直接返回结果。
-
递归情况(Recursive Case):在递归情况中,函数将问题分解成更小的子问题,并自我调用来解决这些子问题。每一层递归都依赖于其下一层的结果,直到达到基本情况,然后逐层返回计算结果。
递归函数的优缺点:
优点:
- 适合于树形遍历
- 代码长度小
缺点:
- 消耗相对更多的栈内存
- 运行速度可能变得更慢
- 实现和debug变得更为困难