(1)内联函数
1.含义
C++编译器可以将⼀个函数进⾏内联编译,只需要在函数定义时前⾯加上inline即可。被C++编译器内联编译的函数叫做内联函数。内联函数在最终⽣成的代码中是没有定义的。C++编译器直接将函数体插⼊在函数调⽤的地方。
#include <stdio.h>inline int myfunc(int a, int b)
{printf("a = %d\n", a);printf("b = %d\n", b);return (a < b) ? a : b;
}int main()
{int a = 1;int b = 3;int c = myfunc(a , b);return 0;
}/*
int main()
{int a = 1;int b = 3;printf("a = %d\n", a);printf("b = %d\n", b);int c = (a < b) ? a : b;return 0;
}
*/
内联函数说明:
- 内联函数省去了普通函数调⽤时压栈,跳转和返回的开销,速度更快。当函数体的执⾏开销远⼤于压栈,跳转和返回所⽤的开销 时,那么内联将⽆意义。
- C++编译器不⼀定准许函数的内联请求!内联函数是对编译器的⼀种请求,因此编译器可能 拒绝这种请求。
- 现代C++编译器能够进⾏编译优化,因此⼀些函数即使没有inline声明,也可能被编译器内 联编译。
C++中内联编译的限制:
- 不能存在任何形式的循环语句
- 不能存在过多的条件判断语句
- 函数体不能过于庞⼤
- 不能对函数进⾏取址操作
- 函数内联声明必须在调⽤语句之前
- inline只是⼀种请求,编译器不⼀定允许这种请求
2.使用内联函数替代宏代码片段
C++中的const常量可以替代宏常数定义,如:
const int A = 3; 与 #define A 3
C++中是否有解决⽅案替代宏代码⽚段呢?(替代宏代码⽚段就可以避免宏函数的副作⽤)
C++中推荐使⽤内联函数替代宏代码⽚段
内联函数声明时inline关键字必须和函数定义(函数体)结合在⼀起,否则编译器会直接忽略内联请求。
#include <iostream>#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);std::cout << a << "," << b << "," << c << std::endl; // 3,3,2/*为什么当 int c = MYFUNC(a++, b); 时是a = 3, c = 2MYFUNC(a++, b) → (a++ < b) ? a++ : ba++先取值再自增 取值是1,自增后 a = 2,1小于b所以返回 a++ ,返回的这个a++先取值就是2,再自增就是3所以 a = 3, c = 2*/int x = 1;int y = 3;int z = myfunc(x++, y);std::cout << x << "," << y << "," << z << std::endl; // 2,3,1/* 为什么当 int z = myfunc(x++, y); 时是 x = 2, z = 1x++传入实参 先返回值,也就是1,所以a为11和3比较返回1,所以z = 1*/return 0;
}
(2)默认参数
C++中可以在函数声明时为参数提供⼀个默认值, 当函数调⽤时没有指定这个参数的值,编译器会⾃动⽤默认值代替。
普通参数放在函数参数位置的左边,默认参数放在右边,默认参数右边必须全是默认参数。
#include <iostream>void test(char pos, int a = 0, int b = 0)
{std::cout << pos << "," << a << "," << b << std::endl;
}int main()
{test('S'); // S,0,0test('K', 10); // K,10,0test('N', 3, 2); // N,3,2return 0;
}
(3)占位参数
函数占位参数:占位参数只有参数类型声明,⽽没有参数名声明。⼀般情况下,在函数体内部⽆法使⽤占位参数。
#include <iostream>int func(int a, int b, int)
{return a + b;
}int main()
{int ret = func(1, 2, 5);std::cout << ret << std::endl; // 3return 0;
}
可以将占位参数与默认参数结合起来使⽤,作用:
- 为以后程序的扩展留下线索
- 兼容C语⾔程序中可能出现的不规范写法
#include <iostream>int func2(int a, int b, int=0)
{std::cout << a << "," << b << std::endl;
}int main()
{func2(1, 2); // okfunc2(1, 2, 100); // okreturn 0;
}
(4)函数重载
1.含义
概念:⽤同⼀个函数名定义不同的函数。当函数名和不同的参数搭配时函数的含义不同。
函数重载⾄少满⾜下⾯的⼀个条件:
- 参数个数不同
- 参数类型不同
- 参数顺序不同
返回值 不是 判断函数重载的标准
// main.cpp
#include <stdio.h>void myPrint(int a)
{printf("a = %d \n", a);
}void myPrint(char *p)
{printf("%s \n", p);
}void myPrint(int a, int b)
{printf("a = %d ", a);printf("b = %d \n", b);
}int main()
{myPrint(1);char name[] = "111222233aaaa";myPrint(name);myPrint(1, 2);return 0;
}
2.函数重载和函数默认参数的二义性报错
#include <iostream>// 函数重载 和 函数默认参数 在一起
void myfunc(int a, int b, int c = 0)
{std::cout << a << "," << b << "," << c << std::endl;
}void myfunc(int a, int b)
{std::cout << a << "," << b << std::endl;
}int main()
{myfunc(1, 2); //函数调用时,会产生二义性// 报错:错误:调用重载的‘myfunc(int, int)’有歧义return 0;
}
3.函数重载和函数指针结合
当使⽤重载函数名对函数指针进⾏赋值时
根据重载规则挑选与函数指针参数列表⼀致的候选者
严格匹配候选者的函数类型与函数指针的函数类型
#include <iostream>
#include <cstring>
using namespace std;int func(int x)
{return x;
}int func(int a, int b)
{return a + b;
}int func(const char *s)
{return strlen(s);
}typedef int (*PFUNC)(int a); // 函数指针声明int main()
{int c = 0;PFUNC p;p = func;c = p(1); // 根据类型进行匹配,选择int func(int x)std::cout << c << std::endl; // 1// std::cout << p(1, 6) << std::endl; // 会报错// 在第一次p=func以及c = p(1)后,根据重载规则// p的地址已经确定,是int func(int x)函数的地址,因此这里报错return 0;
}
end