1.内联函数
(1)内部链接的函数,能在编译期间进行代码展开的函数
PC程序计数器,指令一条一条运行 PC+1
当遇到一个函数如fun(),PC停在那个位置,跳转运行fun(),运行完,PC+1
fun()函数的生命周期只有一行
跳转运行函数很浪费资源和时间
inline int add(int a,int b) //内联函数
{
return a+b;
}
int main()
{
int a=add(10,20);//当调用内联函数时,会自动把函数里的内容替换到主函数里 //既不影响程序可读性和封装性,也不浪费资源 //函数名→函数主体
}
(2)限制:
内联函数中不可含有循环:展开会使代码量变得非常多
内联函数中不可能含有静态变量:静态变量的生命周期函数结束时不会结束,代码每次展开都会多一个静态变量
内联函数不可为递归函数
内联函数不可含有错误处理
①长度较长的函数不能声明为内联函数(不要超过5行,循环和递归)
②具有共用生命周期的变量的函数不能生命为内联函数(静态变量和异常处理)
(3)定义必须是在第一次调用之前
2.默认参数
C++在函数声明时允许对形参进行赋初值
int add(int a=1,int b=2) //默认参数
{
return a+b;
}
int main()
{
cout<<add()<<endl;
retunr 0;
}
防止反编译:使用add()不放参数,实际上需要参数,不可以通过反编译反推函数实现
当出现第一个默认参数时,后面的形参也必须是默认参数
int add(int a,int b=2,int c) //错误,c也必须是默认参数
3.函数占位参数
占位参数:没有函数名,占个位置的参数
int add(int a,int b,int)
占位参数没有意义,但调用必须放进去
add(1,2,3) ✔
add(1,2) ×
占位参数和默认参数混用int add(int a,int b,int =0)
add(1,2,3) ✔
add(1,2) ✔
一个函数的形参列表有多种写法
4.函数重载
一种接口,多种实现(相同的函数名,不同的函数主体,不同的函数实现)
int add(int a,int b) //C语言里可以有相同的函数名
{
return a+b;
}
float add(float a,float b)
{
return a+b;
}
char add(char a,char b)
{
return a+b;
}
//根据传参不同调用不用函数
int main()
{
cout<<add(1,2)<<endl;
cout<<add(1.2f,3.4f)<<endl;
cout<<add('0','1')<<endl;
return 0;
}
C语言里预处理 宏定义的替换 函数名的修改
fun→_fun 没有办法进行函数重载
C++里fun(int ,int ) →_int _int_fun
参数个数不同
参数类型不同
参数顺序不同
仅仅返回值不同,不可以构成重载!!!
int add(int a,int b)
float add(int a,int b)
默认参数在预处理修改函数名时不会纳入函数名
int fun(int a,int b)
int fun(int a,int b,int c=3) →_int _int_fun
add(1,2)会产生歧义
默认参数不可以重载
占位参数可以重载 占位参数占位
函数指针
函数指针可以精确地匹配重载函数
5.C++的类型转换运算符
C语言类型转换:
int a=97;
printf("%c\n",(char)a);//不会检查类型转换是否安全
补充:
比如int a=129;
char b=a;
//129超出char的取值范围,在char里值为-127,但在C语言里并不会检查这种错误
129低八位为原码10000001 补码10000001
转化为char第八位变成符号位,不变,对应反码为10000000(补码-1),对应原码即11111111,为-127
static_cast:
可用:
①具体普通类型的转换
②void*和其他类型指针之间的转换
不可用:
①不可用于具体类型指针之间的转换
②不可用于具体地址转换成指针
int a=129;
char b=static_cast<char>(a);//窄信息转换,可能会产生信息丢失
long c=static_cast<long>(a);//长信息转换,信息不会丢失
cout<<b<<endl;
cout<<c<<endl;
int *p=static_cast<int*>(malloc(sizeof(int)));//将void*转换为int *型的指针
void *p1=static_cast<void*>(p);//将int *转成void*
//不被允许的转换
//float *p2=static_cast<float*>(p);//具体类型的转换不被允许
//p=static_cast<int*>(0×ffff);//不可以转换具体的地址,程序员使用的地址是逻辑地址
//程序员很难确定正确的地址
//如何给固定地址的内存赋值?
void *p=(void*)(0xffff);//c语言里可以这么做
const_cast:将const类型转换成非const
const int a=100;
int *p=const_cast<int*>(&a);
*p=200;
cout<<a<<endl; //a=100,内存里的a确实被修改了,但编译时不会从内存里取a
cout<<*p<<endl; //*p=200
return 0;
reinterpret_cast:重新解释转换,暴力转换,非常的危险
int main()
{
char str[]="hello";
int *p=reinterpret_cast<int*>(str);//任何类型转换成任何类型
cout<<*p<<endl;
int a=100;
int *p1=reinterpret_cast<int*>(a);
cout<<*p1<<endl;
}
dynamic_cast:
dynamic_cast会检查转换的对象是否真的可以转换成目标类型,这种检查不是语法上的,而是真实情况的检查