c/c++ 的区别
一.函数的默认值
在C语言里函数的参数是不能够带默认值的。比如int func(int a, int b = 1);这样的声明就是不正确的。但是在C++中上述的声明是被允许的
函数的默认参数值,即在定义参数的时候同时给它一个初始值。在调用函数的时候,我们可以省略含有默认值的参数。也就是说,如果用户指定了参数值,则使用用户指定的值,否则使用默认参数的值。
1.默认值一般写在声明中(一般声明在调用之前(声明 调用 定义为一般位置) 若有实参 实参会替代默认值 若无实参 则用默认值)
#include <iostream>
using namespace std;
int max(int a, int b, int c=0);//函数声明,形参c有默认值
int main( )
{
int a,b,c;
cin>>a>>b>>c;
cout<<″max(a,b,c)=″<<max(a,b,c)<<endl; //输出3个数中的最大者
cout<<″max(a,b)=″<<max(a,b)<<endl; //输出2个数中的最大者
return 0;
}
int max(int a,int b,int c) //函数定义
{
if(b>a) a=b;
if(c>a) a=c;
return a;
}
运行情况如下:
14 -56 135↙
max(a,b,c)=135
max(a,b)=14
若在定义时而不是在声明时置默认值,那么函数定义一定要在函数的调用之前。因为声明时已经给编译器一个该函数的向导,所以只在定义时设默认值时,编译器只有检查到定义时才知道函数使用了默认值。若先调用后定义,在调用时编译器并不知道哪个参数设了默认值。所以我们通常是将默认值的设置放在声明中而不是定义中。
2.自右向左依此赋值
3.默认值只能赋一次(否则编译器会产生二义性 会报错)
4.默认值的限制
(1)不能使用局部变量(不符合语法规则 调用时看不到下面定义的局部变量
(2)能使用全局变量(静态全局变量也可以)
(3)能使用函数
二.函数重载
在实际开发中,有时候我们需要实现几个功能类似的函数,只是有些细节不同。例如希望交换两个变量的值,这两个变量有多种类型,可以是 int、float、char、bool 等,我们需要通过参数把变量的地址传入函数内部。在C语言中,程序员往往需要分别设计出三个不同名的函数
但在C++中,这完全没有必要。C++ 允许多个函数拥有相同的名字,只要它们的参数列表不同就可以,这就是函数的重载(Function Overloading)。借助重载,一个函数名可以有多种用途。
参数列表又叫参数签名,包括参数的类型、参数的个数和参数的顺序,只要有一个不同就叫做参数列表不同。
重载就是在一个作用范围内(同一个类、同一个命名空间等)有多个名称相同但参数不同的函数。重载的结果是让一个函数名拥有了多种用途,使得命名更加方便(在中大型项目中,给变量、函数、类起名字是一件让人苦恼的问题),调用更加灵活。
在使用重载函数时,同名函数的功能应当相同或相近,不要用同一函数名去实现完全不相干的功能,虽然程序也能运行,但可读性不好,使人觉得莫名其妙。
注意,参数列表不同包括参数的个数不同、类型不同或顺序不同,仅仅参数名称不同是不可以的。函数返回值也不能作为重载的依据。
1.c++函数符号生成的规则
(1)返回值 (2)函数名 (3)参数列表(个数 类型 顺序)
c语言中不允许存在函数名相同的函数 而c++是允许的 两种语言函数符号生成规则不同
2.函数重载的三要素规则
(1)同作用域(同一个类、同一个命名空间等)
(2)函数名称必须相同
(3)参数列表必须不同(个数不同 类型不同 参数排列顺序不同等)。
函数返回类型可以相同也可以不相同,仅仅返回类型不同不足以成为函数的重载。
C++的符号生成规则为函数重载提供了支持 但函数重载不依赖与符号生成规则(函数重载与返回值无关)
3.注意事项:
函数名相同 参数列表相同返回值不同不能构成函数重载;
一个函数不能既做默认值 又做函数重载;
C++ 是如何做到函数重载的
C++代码在编译时会根据参数列表对函数进行重命名,例如void Swap(int a, int b)会被重命名为_Swap_int_int,void Swap(float x, float y)会被重命名为_Swap_float_float。当发生函数调用时,编译器会根据传入的实参去逐个匹配,以选择对应的函数,如果匹配失败,编译器就会报错,这叫做重载决议(Overload Resolution)。
三.Inline内联函数
内联函数:内联函数是浪费空间来节省时间的设置,因为函数的调用是很浪费时间的,写成内联函数可以在每次调用时用函数体内容代替函数调用,有点类似一个宏定义。当函数体语句较少,且没有复杂的循环语句,且调用次数较多时,就可以用内联函数。
内联函数处理在编译阶段 比宏更安全;展开函数不用清栈和开栈 没有函数压栈开销 内联函数提升程序运行的效率。因此,内联函数的运行速度比常规函数稍快,但代价是需要占用更多内存。关键字inline必须与函数定义体放在一起才能使函数称为内联
对于经常要使用的代码段,为了方便使用会将其封装成函数。然而在调用函数时会建立栈帧,增加了额外的开销。为了节省开销,在C语言中会使用宏替换。然而宏具有一些缺点:
(1)不能调试;
(2)由于宏使用简单的文本替换,对于有些情况,在同一个作用域中同一个宏使用两次会出现重定义错误。
内联函数的设计位置:一般写在头文件下
问:为什么不把所有函数都处理成内联函数?
如果所有函数都处理成内联函数 都展开生成的可执行文件的代码太大 开销太大 典型的空间换时间
1.内联函数以代码膨胀为代价(以空间换时间)
当函数堆栈调用 > 函数执行的开销 此时代码少 函数体小 因此建议使用内联函数;
当函数堆栈调用 < 函数执行的开销 此时代码多 不建议使用内联函数;
2.比较inline内联函数与static函数
(1)inline函数无开栈清栈过程 而static函数有开栈清栈过程
(2)inline函数不生成函数符号 而static生成函数的局部符号(仅在当前文件可见)
3.内联函数的注意事项
(1)inline函数对编译器而言只是一个建议
(2)如果定义的函数体内有递归 循环while switch等 编译器优化时会自动忽略掉内联
(3)inline函数在debug版本下不生效 在release版本下生效
(4)inline函数是基于实现的 不是基于声明的
四.c/c++接口的相互调用
extern "C"是C++的特性,是一种链接约定,它并不影响调用函数的定义,即使做了该声明,对函数类型的检查和参数转换仍要遵循C++的标准,而不是C。主要是为了解决C++在调用C函数库时,用C++直接链接就会出现不能识别符号的问题,而用上extern "C"后,告诉C++编译器要以C语言的方式编译和链接函数,即直接使用函数名而不是一个经过处理的函数名。
int Sum( int a , int b ); .c文件产生的是_Sum
int Sum( int a , int b ); .cpp文件产生的是_Sum_int_int
1.c++调用c的接口
在.cpp文件中加extern “C”
2.c调用c++的接口
(1)修改c++文件
.cpp文件中加extern”C”
(2)不修改c++文件
加中间层处理
别人写好的链接库show.so 是不能修改的 没法直接调用链接库 于是加上中间层即可解决 中间层是我们自己写的.cpp文件 这时就可以修改了 调用show函数即可 并加上extern”C” 此时.cpp文件转换成了.c文件 在main.c里在调用Myshow()即可
3.源文件不确定什么编译器编译
加宏 :#ifdef __cplusplus
五.c/c++中const的区别
1.在c语言中 const修饰的是常变量
常变量不能做左值 其他和普通变量的处理方式相同(例如解引用 修改值等功能 只是不能做左值而已)
2.在c++中 const修饰的是常量
(1)常量不允许修改 一定要初始化值
(2)不允许普通的指针指向(有风险被解引用从而被修改)
因此要用常量指针指向:const int * p = &a;//不允许修改值
对比:
const int *a= &b;//const 在*左边,指针指向的内容为常量 即a的内容为常量 不可修改值
int *const a=&b;//const在*号的右边,表明指针a是常量不能进行修改,但是a指的内容是可以修改的
const int *const a=&b;//const在*号的两边都有,表明指针a是常量不能进行修改,但是a指的内容是也不可以修改的 在编译阶段
把用到常量的地方替换成常量初始化的值 因此不管中间再怎么人为修改 也不会改变值 因此很安全
c++中用const定义了一个常量后,不会分配一个空间给它,而是将其写入符号表(symbol table),这使得它成为一个编译期间的常量,没有了存储与读内存的操作,使得它的效率也很高。
在编译阶段把用到常量的地方替换成常量初始化的值 因此不管中间再怎么人为修改 也不会改变值 因此很安全
通过 int*p = (int*)(&a);这种方法,可以直接修改const常量对应的内存空间中的值,但是这种修改不会影响到常量本身的值,因为用到a的时候,编译器根本不会去进行内存空间的读取。这就是c++的常量折叠(constant folding),即将const常量放在符号表中,而并不给其分配内存。编译器直接进行替换优化。除非需要用到a的存储空间的时候,编译器迫不得已才会分配一个空间给a,但之后a的值仍旧从符号表中读取,不管a的存储空间中的值如何变化,都不会对常量a产生影响。