- 类型转换
- 隐式类型转换
又称自动类型转换,它是由编译器自动进行的。转换的规则按'存储空间提升原则'进行,即存储空间小的类型转换成存储空间大的类型,或精度低的类型转换成精度高的类型,以保证运算结果尽可能精确。
char,short -> int -> unsigned -> long -> double
float -> double - 显式类型转换
人为进行强制类型转换,如(int) (x+y)
- 参数传递机制
- 值传递
形参作为被调函数的内部变量来处理,即开辟内存空间以存放由主调函数复制过来的实参的值,从而成为实参的一个副本。值传递的特点是被调函数对形参的任何操作都是对内部变量进行的,不会影响到主调函数的实参变量的值。 - 引用传递
被调函数的形参虽然也作为内部变量开辟了内存空间,但是这时存放的是由主调函数复制过来的实参的内存地址,从而使得形参为实参的一个别名(形参和实参的内存地址相同,则它们是同一个对象的两个名称)。被调函数对形参的任何操作实际上都是对主调函数的实参进行操作。
- 函数调用栈
函数调用时,为了能将参数传递到函数中,准确地返回到调用点以及返回函数值,使用栈来管理存储器。
系统为每次函数调用在栈中建立独立的栈框架,称为函数调用栈帧,其建立和撤销是自动维护的。
函数调用约定最右边的实参最先进栈。 - const参数和可变参数
const限定一个对象不允许被修改。
函数参数使用const限定的目的是确保形参对应的实参对象在函数体中不会被修改。对于基本类型的参数,实参和形参本来就不是同一个内存单元,互不影响,不用加const。但是如果是数组参数,指针参数就有必要了。
形参至少需要第一个参数是普通形参,后面用三个点表示可变参数,且只能位于函数形参列表的最后。 - 内联函数
函数调用时参数需要入栈,调用前需要保护现场并保存返回地址,调用后需要恢复现场并按原来保存的返回地址继续执行。因此函数调用需要时间和空间开销,影响执行效率。
C++提供一种提高函数效率的方法,即在编译时将被调函数的代码直接嵌入到主调函数中,取消调用这个环节。这种嵌入到主调函数中的函数称为内联函数,在函数定义的类型前加inline修饰符。
内联函数是以目标代码的增加为代价来换取运行时间的节省。内联函数中不允许用循环语句和switch语句,递归函数也不能被用来做内联函数。 - 带默认参数的函数
默认参数在函数声明或者函数定义中只能设置一次,也就是编译器见到过一次函数设置默认参数,后面就不允许再次出现这个函数的默认参数设置。
可以设置多个默认参数,但是设置顺序为自右向左。
默认参数允许同一个函数名有多种调用方法。 - 函数重载
在同一个域中的同一个函数名可以用来定义多个函数,但函数参数列表应彼此不同:参数个数不同,参数类型不同,或者两者均不同。
编译器根据参数类型和参数个数自动解析决定调用哪个版本的重载函数。 - 函数模板
函数模板定义一个通用型函数,这些函数与类型无关,并且只在需要时自行实例化,从而形成批量型的编程方式。
定义语法:
template<模板形参表> 返回类型 函数名(形式参数列表)
{
函数体
}
template<typename T>T add(T a, T b)
{
return a+b
}
- 函数调用形式
嵌套调用:在调用一个函数的过程中该函数又调用另一个函数,称为函数嵌套调用。
递归调用:函数直接或间接调用自己。可以这样理解函数调用自己:实际上它在调用自身的一个副本,该副本是具有不同参数的另一个函数,任何时候只有一个副本是活动的,其余的都将被挂起。 - 作用域
局部变量:在函数内部或复合语句中定义的变量。局部变量只能在定义它的区域及其子区域中使用。
全局变量:在函数外部定义的变量。全部变量的有效区域是从定义变量的位置开始到源文件结束。
可以使用extern声明将变量或函数实体的可见区域往前延伸,称为前置声明。
在全局作用域中,变量或函数实体若使用static修饰,则该实体对于其他源文件是屏蔽的,称为私有的(private)。 - 程序映像和内存布局
C++源程序经过编译和链接后,成为二进制形式的可执行文件,称为程序映像。运行程序时,由操作系统将可执行文件装入计算机内存中,成为一个进程,程序在内存中的布局由5个段组成(内存地址由低到高):
代码段
代码段存放程序执行的机器指令,可共享用来被频繁执行,通常是只读的防止被意外的修改。已初始化的数据段
存放C++程序中所有已赋初值的全局和静态变量、对象,也包括字符串、数组等常量,但是基本类型的常量不包含在其中,因为这些常量被编译成指令的一部分存放在代码段中。该段存储单元的初始值在程序没有运行时就固定下来了,在程序运行时没有初始化操作。未初始化的数据段
存放C++程序中所有未赋初值的全局和静态变量,数据值全都初始化为0。栈
放C++程序中所有局部的非静态型变量、临时变量、包含函数形参和返回值。
在程序映像中没有栈,在程序开始运行时也不会分配栈。函数调用时开始得到分配,将函数栈框架入栈,函数调用结束时释放空间,变量不存在。-
堆
存放C++程序中动态分配的存储空间。
在程序映像中没有堆,在程序开始运行时也不会分配堆,函数调用时也不会分配堆。堆的存储空间是由程序员使用指令分配和释放。堆和栈的共同点是动态存储,处于这两个区域的存储单元可以随时分配和释放,呈现临时性的特点。区别是分配方式不同,栈是编译器根据程序代码自动确定大小,到函数调用时由指令自动完成分配和释放;堆则完全由程序员指定分配大小,何时分配,何时释放,自行掌握分配和释放时机,假如已经释放了还使用堆会产生引用错误,或者始终没有释放会产生内存泄露。
内存溢出:程序在申请内存时,没有足够的内存空间可使用。你要求分配的内存超出了系统能给你的。
内存泄露:程序动态申请的堆内存由于某种原因未释放或无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃。
- 静态局部对象
在局部对象的前面加上static修饰
静态局部对象和全局变量一样按静态存储处理,即它的生命期与程序运行期相同,所有静态局部对象可以将其值一直保持到程序结束或者下次修改。
静态局部对象和全局对象的区别是它的作用域是块作用域,只能在局部区域使用。静态局部对象在还未调用函数前甚至是程序运行时就进行初始化了,所以每次调用时不会再有初始化操作。如果静态局部对象定义时未赋初值,则用0填充。
当一个函数会被多次调用又希望它的某些值保持住时,就因该使用功能静态局部对象。需要注意全局对象定义前加上static不是静态的意思,全局本身已是静态,而是私有的意思,此时全局对象的作用域为该源文件。 - 程序组织结构
- 内部函数
函数本质上是全局的,在函数定义前面加上static修饰,称其为内部函数,仅在包含它的文件中可见。 - 外部函数
在函数定义前加上extern修饰,称其为外部函数,在调用另一个文件中的函数时,需要用extern声明此函数是外部函数,C++中所有的函数本质上都是外部函数,所有extern可以省略。