c/c++区别(一)函数的默认值 函数重载 内联函数 c/c++接口调用 const在c/c++的区别

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产生影响。

猜你喜欢

转载自blog.csdn.net/xiaobaibai915/article/details/84000073
今日推荐