使用函数有利于代码重用,可以提高开发效率,增强程序的可靠性,也便于分工合作,便于修改维护。但是,函数调用也会降低程序的执行效率,增加时间和空间方面的开销。因此对于一些功能简单、规模较小又使用频繁的函数,可以设计为内联函数。内联函数不是在调用时发生控制转移,而是在编译时将函数体嵌入在每一个调用处。这样就节省了参数传递、控制转移等开销。
内联函数的定义与普通函数的定义方式几乎一样,只是需要使用关键字inline,其语法形式如下:
inline 类型说明符 函数名(含类型说明的形参表)
{
语句序列
}
需要注意的是,inline关键字只是表示一个要求,编译器并不承诺将inline修饰的函数作为内联。而在现代编译器中,没有用inline修饰的函数也可能被编译为内联。通常内联函数应该是比较简单的函数,结构简单、语句少。如果将一个复杂的函数定义为内联函数,反而会造成代码膨胀,增大开销。这种情况下,多数编译器都会自动将其转换为普通函数来处理。到底什么样的函数会被认为太复杂呢?不同的编译器处理起来是不同的。此外,有些函数是肯定无法以内联方式处理的,例如存在对自身直接递归调用的函数。
内联函数应该一股脑的放在头文件当中!
#include
using namespace std;
const double PI=3.14159265358979;
//内联函数,根据圆的半径计算其面积
inline double calArea(double radius)
{
return PI*radius*radius;
}
int main()
{
double r=3.0; //r是圆的半径
//调用内联函数求圆的面积,编译时此处被替换为calArea函数体语句
double area=calArea(r);
cout<<area<<endl;
return 0;
运行结果:
28.2743
函数在定义时可以预先声明默认的形参值。调用时如果给出实参,则用实参初始化形参,如果没有给出实参,则采用预先声明的默认形参值。例如:
int add(int x=5,int y=6)//声明默认形参值
{
return x+y;
}
int main()
{
add(10,20); //用实参来初始化形参,实现10+20
add(10); //形参x采用实参值10,y采用默认值6,实现10+6
add();
}
有默认值的形参必须在形参列表的最后,也就是说,在有默认值的形参右面,不能出现无默认值的形参。因为在函数调用中,实参与形参是按从左向右的顺序建立对应关系的。例如:
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);//错误
在相同的作用域内,不允许在同一个函数的多个声明中对同一个参数的默认值重复定义,即使前后定义的值相同也不行。这里作用域是指直接包含着函数原型说明的大括号所界定的范围。注意,函数的定义也属于声明,这样,如果一个函数在定义之前又有原型声明,默认形参值需要在原型声明中给出,定义中不能再出现默认形参值。
例如:
int add(int x=5,int y-6); //默认形参值在函数原型中给出
int main()
{
add();
return 0;
}
int add(int x/*=5*/,int y/*=6*/)
{
//这里不能再出现默认形参,但为了清晰,可以通过注释说明默认形参
return x+y;
}
像这样在函数的定义处,在形参表中以注释来说明参数的默认值,是一种好习惯。
首先结论:
1.引用不占空间,指针占8字节空间;
2.引用必须初始化,而指针不必;
3.引用在被绑定以后,这种绑定关系是不能被拆解的。
引用是一种特殊类型的变量,可以被认为是另一个变量的别名,通过引用名与通过被引用的变量名访问变量的效果是一样的,例如:
int i,j;
int &ri=i; //建立一个int型的引用ri,并将其初始化为变量i的一个别名
j=10;
ri=j;//相当于i=j;
使用引用时必须注意下列问题:
1.声明一个引用时,必须同时对它进行初始化,使它指向一个已存在的对象。
2.一旦一个引用被初始化后,就不能改为指向其他对象。
也就是说,一个引用,从它诞生之时起,就必须确定是哪个变量的别名,而且始终只能作为这一个变量的别名,不能另作他用。
**引用也可以作为形参,如果将引用作为形参,情况便稍有不同。**这是因为,形参的初始化不在类型说明时进行,而是在执行主调函数中的调用表达式时,才为形参分配内存空间,同时用实参来初始化形参。这样引用类型的形参就通过形实结合,成为了实参的一个别名,对形参的任何操作也就会直接作用于实参。
用引用作为形参,在函数调用时发生的参数传递,称为引用传递。
#include
#include
using namespace std;
void fiddle(int &in1, int &in2) // 使用引用来修改参数的值
{
in1 = in1 + 100;
in2 = in2 + 100;
cout << "The Values Are ";
cout << in1 << ", "; // 使用逗号连接两个输出
cout << in2 << endl;
}
int main()
{
int v1 = 7, v2 = 12; // 修正变量名为 v1
cout << "The values are ";
cout << v1 << ", "; // 使用逗号连接两个输出
cout << v2 << endl;
fiddle(v1, v2); // 修正调用参数
cout << "The values are ";
cout << v1 << ", "; // 使用逗号连接两个输出
cout << v2 << endl;
return 0;
}
运行结果:
The values are 7, 12
The Values Are 107, 112
The values are 107, 112
在程序中,一个函数就是一个操作的名字,正是靠类似于自然语言的各种各样的名字,才能写出易于理解和修改的程序。通常,自然语言中一个词可以代表许多种不同的含义,需要依赖上下文来确定。这就是所谓一词多义,反映到程序中就是重载。
C++语言中提供了对函数重载的支持,使我们在编程时可以对不同的功能赋予相同的函数名,编译时会根据上下文(实参的类型和个数)来确定使用哪一具体功能。
两个以上的函数,具有相同的函数名,但是形参的个数或者类型不同,编译器根据实参和形参的类型及个数的最佳匹配,自动确定调用哪一个函数,这就是函数的重载。如果没有重载机制,那么对不同类型的数据进行相同的操作也需要定义名称完全不同的函数。例如定义加法函数,就必须这样对整数的加法和浮点数的加法使用不同的函数名:
int iadd(int x,int y);
float fadd(float x,float y);
这在调用时实在是不方便。
C++允许功能相近的函数在相同的作用域内以相同函数名定义,从而形成重载。方便使用,便于记忆。
注意 :**重载函数的形参必须不同:个数不同或者类型不同。**编译程序对实参和形参的类型及个数进行最佳匹配,来选择调用哪一个函数。**如果函数名相同,形参类型也相同(无论函数返回值类型是否相同),在编译时会被认为是语法错误(函数重复定义)。**例如:
(1)int add(int x,int y); //形参类型不同
float add(float x,float y);
(2)int add(int x,int y); //形参个数不同
int add(int x,int y,int z);
例如:
(1)int add(int x,int y);
int add(int a,int b);//错误!编译器不以形参名来区分函数
(2)int add(int x,int y);
void add(int x,int y);//错误!编译器不以返回值来区分函数
不要将不同功能的函数定义为重载函数,以免出现对调用结果的误解、混淆。例如:
int add(int x,int y){return x+y;}
float add(float x,float y){return x-y;)
当使用具有默认形参值的函数重载形式时,需要注意防止二义性。例如下面的两个函数原型,在编译时便无法区别为不同的重载形式:
void fun(int length,int width=2,int height=33);
void fun(int length);
也就是说,当以调用函数fun时,编译器无法确定应该执行哪个重载函数,这时编译器会指出语法错误。