声明:该文章是从多个文章中,根据个人的理解,进行了引用,在此特声明,表示感谢!!!
1、 内联函数
内联函数也称内嵌函数。引入内联函数的目的是为了解决程序中函数调用的效率问题。前面我们讲过,函数的引入使得编程者只关心函数的功能和使用方法,而不必关心函数功能的具体实现;另外,函数的引入可以减少程序的代码,实现程序代码和数据的共享。但是函数调用也会带来降低效率的问题,因为调用函数实际上将程序执行顺序转移到函数所存放的内存地址处,将函数的程序执行完毕,再返回到转去执行程序前的地方。这种转移操作要求在转去前保护现场并记忆执行的地址,转回后先要恢复现场,并按原来的保护地址继续执行。因此函数调用是以牺牲时间和空间为代价的。对于一些函数体代码不是很大,但又频繁地被调用的函数来讲,解决其效率问题更为重要。这是引入内联函数的初衷。
在程序编译时,编译器将程序中出现的内联函数的调用表达式用内联函数的函数体来进行替换。这种做法不会出现程序转向的问题,但是这样会增加程序的代码量,进而增加空间开销,可见内联函数是以目标代码的增加为代价来换取时间的节省。
①内联函数的定义方法
定义内联函数的方法很简单,只要在函数定义的的头前加上关键字 inline 即可。内联函数的定义方法和普通函数的定义方法相同。
例如: inline int add(int a, int b)
{
return a+b;
}
②内联函数在使用时应注意:
(1)在内联函数中不允许用循环语句和开关语句。
(2) 内联函数的定义必须出现在内联函数第一次被调用前。
(3) 后面讲到的类结构中的所有在类说明内部定义的函数都是内联函数。
(4) 内联函数只适合于一到五行的小程序,对于含有许多语句的大函数,函数调用和返回时的开销相对来说微不足道,没有必要用内联函数。
2、递归调用
在一个函数体中可以调用另一个函数,当被调用函数是这个函数自身或者被调函数中又调用这个函数时,这种调用就是递归调用。前者为直接递归调用,后者称为间接递归调用。例如,在 f1() 函数体内,又调用了 f1() ,或着在函数 f1() 中,调用了 f2() ,而在 f2() 中又调用了 f1(), 着两种情况都属于递归调用。
A:递归调用机制:
⑴任何函数之间不能嵌套定义,调用函数与别调用函数之间相互独立。
⑵发生函数调用时,被调用函数中保护了调用函数的运行环境和返回地址,使得调用函数的状态可以在被调用函数返回后完全恢复,而且该状态与被调用函数无关。
⑶被调用函数栈空间独立于调用函数的栈空间,所以与调用函数之间的数据也是无关的。函数之间靠参数传递和返回值来联系。这种机制决定了 C++ 允许函数递归调用。
B:递归调用的条件
⑴须有完成函数任务的语句。
⑵应有一个条件语句,用以判定递归调用的条件。这是必须的。
⑶有一个递归调用语句。该递归调用语句的参数逐渐逼近不满足条件,以至最后断绝递归。
⑷递归语句应该放在条件语句体中。也就是说递归调用前必须先测试。
C:递归调用的优缺点
优点:
⑴简化程序设计
⑵使程序可读
缺点:
递归增加了系统的开销。时间上,执行调用与返回的额外工作要占用 cpu 时间。空间上,随着每递归一次,栈内存就多占用一些。
3、函数重载
所谓函数重载是指同一个函数名可以对应着多个函数的实现。这样做可以提高程序的可读性,但是那么多的同名函数,在进行实际调用的时候怎么知道调用的是哪一段代码呢?编译器是用函数名加参数的方法来区别函数,就是说,确定函数实现时,要求从函数参数的个数和类型上来区别,这就要求通明函数在参数个数上不同,或者参数类型不同。否则将无法实现函数重载。
A:使用重载函数时应注意:
⑴重载函数不能仅仅是返回类型不同,还必须在参数类型、参数个数和参数顺序上有所不同。
⑵不能用 typedef 定义的类型名来区分重载函数声明中的参数。因为用 typedef 定义的类型只是已有类型的别名而已。
⑶重载函数描述的应该是相同功能,而只是数据类型不同的代码,否则会影响程序的可读性。
⑷当一个函数调用找不到严格相匹配的重载函数时,会将参数进行类型转化,寻求其他匹配。但这时容易出现二义性。
Keil C51使用重载函数:
通常情况下,Cx51函数不能重载调用。这种限制的原因是,函数参数和本地变量都存储在固定的内存地址。重载调用函数将会使用同一内存地址,在这种情况下,参数和本地变量会损坏。
使用可重载函数须做如下声明:
int calc (char i, int b) reentrant { int x; x = table [i]; return (x * b); }