形参带默认值的函数
1.给默认值的时候从右向左给。
2.定义出可以给形参默认值,声明也可以给形参默认值。
3.形参默认值只能出现一次。
4.参数调用的效率问题
#sum(10,20)对应了五条汇编指令 mov eax,dword ptr[ebp-8] push eax mov ecx dword ptr[ebp-4] push ecx call sum #如果调用sum(10)或sum(),则使用默认参数的形参无需mov。
内联函数
普通的函数调用过程会产生的开销:参数压栈、函数栈帧的开辟和回退过程。
如果是大型函数,这些开销尚可无视,但是对于简单函数,这些开销可能就远远大于函数内部的指令的开销了。
Inline内联函数:在编译过程中,就没有函数调用开销了,在函数的调用点会被建议直接把函数代码进行展开处理。文件的符号表中也不会出现inline函数,但是不是所有的inline都会被编译器处理成内联函数,比如递归,inline只是一个建议。
实务注意:debug版本上,inline是不起作用的,在debug的时候把代码展开要出事的;inline只有在release版本下才能拿出现。
Inline内联函数的普通函数的区别:内联成功的函数,少了函数调用开销,不在符号表中出现。
函数重载
定义:一组函数,其中函数名相同,参数列表的个数或类型不同,则称为函数重载。所以如果仅仅是返回值不同的函数不叫函数重载。一组函数称得上重载,一定是先处在相同的作用域当中的。Const或volatile的时候
C++为什么支持函数重载?
C++在产生符号的时候,是函数名+参数列表类型组成的。C语言产生函数符号的时候,是根据函数名产生的。
函数重载与多态的关系?
多态可以分为静态多态与动态多态。其中静态多态是在编译时期就确定了同名函数所采用的定义(形态),也就是函数重载。
C++和C的相互调用?
C++调用自定义C函数:把C函数的声明扩在extern C里面。
C调用自定义C++函数:把C++函数的源码扩在 extern C里面。
引用
引用和指针的差别
引用是一种更安全、更简单的指针。
1.引用是必须要初始化的,相比起指针不会有空转的可能。在汇编层面语法并无差别。
2.引用只有一级引用,指针可以有一级指针也可以有多级指针。
数组的引用
int array[5] = {}; int (&q)[5] = array;
左值引用
它有内存,有名字,可以放在赋值号左边进行修改的就是左值。它可以出现在等号左边和右边。
int a = 10; int &b = a;//a和b都是左值
右值引用
没内存,没名字。指令上必须先产生一个临时量放在寄存器中,使用完毕就从内存中删除。只能出现在等号右边的值。
int &&c = 20;//20是右值 const int &tem = 20;//20是右值。
右值引用变量本身是一个左值,只能用左值因引用来引用它。
不能用一个右值引用变量来引用一个左值。
const
C语言中的Const修饰的变量不能再作为左值。如果没有初始化可能会报错,可能会采用原内存空间的值,具体看编译器。Const被修饰的值叫做常变量,除了不能作为左值,其他规则和普通的变量没有差别。注意,只是不能通过这个常变量作为左值去修改值,但是可以通过提取常变量的内存空间的地址,再通过这个地址间接去修改这个常变量的值。
C++中的const必须初始化。如果初始值是一个立即数,所有出现const常量名字的地方(也就是可以把它当常量使用的地方),在编译的时候都被常量的初始化替换,这个功能类似于宏替换。但是程序运行的时候,这个被修饰的变量,性质就和C语言中一样了。如果初始值是一个变量,性质也和C语言中一样了。
C++中const修饰的经常出现的错误:
- 把修饰的量作为左值。
- 把修饰的量的地址泄露给普通变量(如果要泄露给普通变量需要做类型转换)。
C++中的Const 与一级指针的结合
C++的语言规范:const修饰的是离它最近的数据类型。
#const int *p和int const *p限制的int const int x = 5; const int *p = &x; *p = 10; // 错误:试图修改指向的值 p++; // 正确:修改指针本身 #int *const p限制的是int * int x = 5;吗不能、‘’ int *const p = &x; *p = 10; // 正确:修改指向的值 p++; // 错误:试图修改指针本身
const如果右边没有指针*的话,const是不参与类型的。
比如const int *p,p的类型是const int*;int * const p的类型是int *。
New和delete
New和malloc:new不仅可以做内存开辟,还可以做内存初始化操作。Malloc开辟内存失败是通过返回值和nullptr做比较;而new开辟内存失败,是通过抛出bad_alloc类型的异常来做判断,可以通过try_catch语法检测异常。New出来的空间要释放用delete,malloc出来的空间释放要用free。
int *q1 = new int[20]; delete[] q1; int num = new int(20); delete q1;