1、inline内联函数
C++中的const常量可以代替宏定义
const int A = 3; #define A 3
在C++中推荐使用内联函数代替宏代码片段
C++中使用inline关键字来声明内联函数
内联函数声明时inline关键字必须和函数定义结合在一起,否则编译器会直接忽略函数的内联申请
#include "iostream"
using namespace std;
#define MYFUNC(a, b) ((a) < (b) ? (a) : (b))
inline int myfunc(int a, int b)
{
return a < b ? a : b;
}
int main()
{
int a = 1;
int b = 3;
//int c = myfunc(++a, b); //头疼系统
int c = MYFUNC(++a, b);
printf("a = %d\n", a);
printf("b = %d\n", b);
printf("c = %d\n", c);
system("pause");
return 0;
}
说明1;
必须inline int myfunc(int a, int b)和函数体的实现,写在一起
说明2:
C++编译器可以对一个函数进行内联编译,被C++编译器内联编译的函数叫做内联函数
内联函数在最终生成的代码中是没有定义的,C++编译器在编译时直接将函数体插入到函数调用的地方
内联函数没有普通函数调用时的额外开销(压栈、跳转、返回等)
说明3:
C++编译器比一定会准许函数的内联申请
说明4:
内联函数是一种普通的函数,具有普通函数的特征(参数检查、返回类型等)
内联函数是对编译器的一种请求,因此C++编译器可能会拒绝这种请求
内联函数是由编译器处理直接将编译后的函数体插入到函数调用的地方
宏代码片段有预处理器处理,进行简单的文本替换,没有进行任何编译过程
说明5:
现代C++编译器能够进行编译优化,因此一些函数几遍没有使用inline声明,也可能被编译器进行内联编译
说明6:
C++中内联编译的限制:
不能存在任何形式的循环语句
不能存在过多的条件判断语句
函数体不能过于庞大
不能对函数进行取址操作
函数内联声明必须在调用语句之前
编译器对于内联函数的限制并不是绝对的,内联函数相比于普通函数的的优势只是省去了函数调用时的压栈、跳转、返回等开销
因此,当函数体的执行开销大于压栈、跳转和返回的开销时,内联函数将毫无意义
总结
1)内联函数在编译时直接将函数体插入到韩束调用的地方
2)内联只是一种一种请求,编译器不一定允许这种请求
3)内联函数省去了普通函数调用时的压栈、跳转、返回等开销
2、默认参数
C++可以在函数声明时为参数提供一个默认值,当函数调用时没有制定参数的值时,编译器会自动用默认值代替
函数默认参数的规则
只有参数列表后面部分的参数才可以提供默认参数值
一旦在一个函数调用中开始使用默认参数值,那么这个参数后的所有参数都必须使用默认参数值
//1、调用函数时若填写参数则使用填写的参数,若不填写则按照默认的
void myprint(int m, int n, int x = 3, int y = 4)
{
cout << x << endl;
}
//2、默认参数规则,如果默认参数出现,则右边的必须都有默认参数
void myprint2(int x = 3)
{
cout << x << endl;
}
void main()
{
myprint();
myprint(4);
cout << "hello..." << endl;
system("pause");
return;
}
3、占位参数
/*
函数占位参数
占位参数只有参数类型声明,而没有参数名声明
一般情况下,在函数体内部无法使用占位参数
*/
void func(int x, int y, int)
{
cout << "x:" << x << " y:" << y << endl;
}
void main()
{
func(2, 3); //报错err
func(2, 3, 4);
cout << "hello..." << endl;
system("pause");
return;
}
也可以将占位参数与默认参数结合起来使用
意义
为以后程序的扩展留下线索
兼容C语言程序中可能出现的不规范写法
*/
//C++可以声明占位符参数,占位符参数一般用于程序扩展和对C代码的兼容
//占位参数有默认值
void func(int x, int y, int = 0)
{
cout << "x:" << x << " y:" << y << endl;
}
void main()
{
func(2, 3); // OK
func(2, 3, 4); //ok
cout << "hello..." << endl;
system("pause");
return;
}
结论://如果默认参数和占位参数在一起,都能调用起来
4、函数重载
#include <iostream>
using namespace std;
void myprintf(int a)
{
printf("a:%d\n", a);
}
void myprintf(char *p) //函数的参数类型不一样
{
printf("%s\n", p);
}
void myprintf(int a, int b)//函数的参数个数不一样
{
printf("a:%d\n", a);
printf("b:%d\n", b);
}
//1、函数名和不同的参数搭配时函数的含义不同
//2、函数重载的判断标准
// 名称相同,参数不一样(类型、个数)
//3、返回值不是判断函数重载的标准
int main()
{
myprintf(1);
myprintf("yangyun\n");
myprintf(1,2);
system("pause");
return 0;
}
函数重载的注意事项
重载函数在本质上是相互独立的不同函数(静态链编)
重载函数的函数类型是不同的
函数返回值不能作为函数重载的依据
函数重载是由函数名和参数列表决定的。
函数重载和函数的默认参数一起
//函数重载和函数的默认参数一起
void myfunc(int a, int b, int c = 0)
{
printf("a=%d b=%d c=%d\n", a, b, c);
}
void myfunc(int a, int b)
{
printf("a=%d b=%d\n", a, b);
}
int main()
{
//myfunc(1,2);//报错err,函数调用时产生二义性
system("pause");
return 0;
}
函数重载和函数指针结合
函数重载与函数指针
当使用重载函数名对函数指针进行赋值时
根据重载规则挑选与函数指针参数列表一致的候选者
严格匹配候选者的函数类型与函数指针的函数类型
//函数重载和函数指针结合
void myprintf(int a)
{
printf("a:%d\n", a);
}
void myprintf(char *p) //函数的参数类型不一样
{
printf("%s\n", p);
}
void myprintf(int a, int b)
{
printf("a=%d b=%d\n", a, b);
}
void myprintf(char* p1, char* p2)
{
printf(p1:"%s\n", p1);
printf("p2:%s\n", p2);
}
//函数指针 基础语法
//1、声明一个函数类型
//void myprintf(int a, int b)
//typedef void (MyTypePrintf)(int a, int b);//定义一个函数类型MyTypePrintf
//MyTypePrintf *myp = NULL; //定义一个函数指针
//2、声明一个函数指针类型
typedef void (*MyTypePrintf)(int a, int b);//声明一个函数指针类型MyTypePrintf
//MyTypePrintf myp = NULL;
//3、定义一个函数指针变量
//void(*myprintf)(int a, int b); //定义一个函数指针变量myprintf
int main()
{
//函数重载和函数指针结合实例
MyTypePrintf myp = NULL; //定义一个函数指针变量
myp = myprintf;
//myp(1);err
myp(1,2); //因为函数指针类型声明时参数是两个int型参数,所以重载时只接受int类型的两个参数
//myp("yang", "yun");err
system("pause");
return 0;
}