一、概述
C++语言有两种编程模块:函数与类。
函数是功能的抽象,函数主要有两个作用:一是任务划分,把一个复杂的任务划分为若干个简单的小任务,便于分工和处理;二是软件重用。
二、如何使用一个函数?
- 提供函数定义
- 提供函数原型
- 调用函数
以下是个简单的例子:
#include <iostream>
using namespace std;
int Add(int,int);//函数原型
int main()
{
int a,b;
cin >> a >>b;
cout << Add(a,b) <<endl;//函数调用
}
int Add(int a,int b)//函数定义
{
return (a+b);
}
1.定义函数
函数可分为两类:没有返回值的函数和有返回值的函数。通用格式如下:
typename Name(parameterList)
{
statement(s);
return value; //value的值与typename有关
}
其中parameterList是函数参数的数量与类型。
当函数定义为void类型时,return语句不带返回表达式或者不使用return语句。
2.函数原型
如果函数定义出现在程序第一次调用之前,则不需要函数声明,因为此时函数定义就具有函数原型的作用。否则,函数原型要写在主函数之前。
为什么需要原型?
函数的原型告诉了编译器函数返回值的类型,参数的类型和数量。当你在调用函数时,若函数的参数类型或个数出现错误,编译器就能捕获这种错误。其次,知道了函数的返回值类型后,编译器才知道应该检索多少个字节以及如何解释他们。
3.参数传递的机制
- 形参:函数定义首部的参数
形参出现在函数定义中,在整个函数体内都可以使用, 离开该函数则不能使用。 - 实参:调用函数时使用的参数
- 三种参数传递机制:值传递、指针传递和引用传递。
#include <iostream>
using namespace std;
void A(int, int);
int main()
{
int a = 1, b = 2;
cout << "调用函数前:";
cout << a << " " << b << endl;
A(a, b);//a和b为实参
cout << "调用函数后:";
cout << a << " " << b;
}
void A(int a, int b)
{
a = 2 * a;//a和b为实参
b = 2 * b;
cout << a << " " << b << endl;
}
以上代码的运行结果如下:
由此可知,调用函数后a和b的值并没有发生变化。
这是因为在函数调用时,实参的值copy到形参,在函数内的所有操作都是对形参进行的。
以上函数的实参和形参为非指针类型,那么当它们为指针类型会发生什么?
#include <iostream>
using namespace std;
void A(int *, int *);
int main()
{
int a = 1, b = 2;
cout << "调用函数前:";
cout << a << " " << b << endl;
A(&a, &b);
cout << "调用函数后:";
cout << a << " " << b;
}
void A(int *a, int *b)
{
*a = 2 * *a;
*b = 2 * *b;
cout << *a << " " << *b << endl;
}
形参与实参的区别:
1.形参变量只有在被调用时才分配内存单元,在调用结束时, 即刻释放所分配的内存单元。因此,形参只有在函数内部有效。 函数调用结束返回主调函数后则不能再使用该形参变量。
2.实参可以是常量、变量、表达式、函数等, 无论实参是何种类型的量,在进行函数调用时,它们都必须具有确定的值, 以便把这些值传送给形参。 因此应预先用赋值,输入等办法使实参获得确定值。
3.实参和形参在数量上,类型上,顺序上应严格一致, 否则会发生“类型不匹配”的错误。
4.函数调用中发生的数据传送是单向的。 即只能把实参的值传送给形参,而不能把形参的值反向地传送给实参。 因此在函数调用过程中,形参的值发生改变,而实参中的值不会变化。
5.当形参和实参不是指针类型时,在该函数运行时,形参和实参是不同的变量,他们在内存中位于不同的位置,形参将实参的内容复制一份,在该函数运行结束的时候形参被释放,而实参内容不会改变。
而如果函数的参数是指针类型变量,在调用该函数的过程中,传给函数的是实参的地址,在函数体内部使用的也是实参的地址,即使用的就是实参本身。所以在函数体内部可以改变实参的值。
三、内联函数与重载函数
1、内联函数
(1)作用:降低小程序调用开销
(2)注意事项:
a.递归函数不能定义为内联函数
b.内联函数一般适合于不存在while和switch等复杂的结构且只有1~5条语句的小函数上,否则编译系统将该函数视为普通函数。
c.内联函数只能先定义后使用,否则编译系统也会把它认为是普通函数。
d.对内联函数不能进行异常的接口声明。
2、重载函数
函数重载是指以同一个名字命名多个函数的实现版本。
重载函数的参数列表至少满足以下条件之一:<1>参数个数不同<2>参数类型不同。
函数返回的类型不是重载条件,例:
int average(int,int);
double average(int,int);
//此时编译器认为函数重复说明