inline函数,缺省函数,函数重载以及函数模板

inline函数

  当程序执行函数调用的时候,系统要建立栈空间,保护现场,传递参数以及控制程序执行的转移等等,这些工作都需要系统事件和空间的开销。

例如以下程序段:

  当函数功能简单,使用频率很高,为了提高效率,直接将函数的代码嵌入到程序当中,但这个办法有缺点,一是相同代码重复书写,而是程序可读性往往没有使用函数的好。

  为了协调好效率和可读性之间的矛盾,c++提供了另外一种方法,即定义内联函数,方法是在定义函数时用修饰词inline。

  加inline关键字将其改成内联函数,在编译期间编译器能够在调用点内联展开该函数。

例如:

   inline是一种以空间换时间的做法,省去调用函数额外开销。但是当函数体的代码过长或者是递归函数即便加上inline关键字,也不会在调用点以内联展开该函数。

  inline对于编译器而言只是一个建议,编译器会自动优化。

  inline不建议声明和定义分离,分离会导致链接错误。因为inline被展开,就没有函数地址了,链接就会找不到。

  所以如果函数的执行开销小于开栈清栈开销(函数体比较小),使用inline处理效率高。如果函数的执行开销大于开栈清栈开销,使用普通函数方式处理。

内联函数和宏定义的区别:

1.内联函数在编译时展开,带参的宏在预编译时展开;

2。内联函数直接嵌入到目标代码中,带参的宏是简单的做文本替换;

3.内联函数有类型检测,语法判断等功能,宏只是替换。

缺省函数

缺省函数是指在定义函数的时候为形参指定缺省值(默认值)。

一般情况下,函数调用时的实参个数应该与形参相同,但是为了方便地使用函数,C++也允许定义具有缺省参数的函数,这种函数调用时,实参个数可以和形参不相同。

这样的函数在调用时,对于缺省参数,可以给出实参值,也可以不给出实参值,如果给出实参值,将实参传递给形参进行调用,如果不给出实参,则按缺省值进行调用。

缺省参数的函数调用:缺省实参并不一定是常量表达式,可以是任意表达式,甚至可以通过函数调用给出。如果缺省实参是任意表达式,则函数每次被调用时该表达式被重新求值。但是表达式必须有意义。

缺省参数可以有多个,但是所有的缺省参数必须放在参数表的右侧,即先定义所有的非缺省参数,再定义缺省参数。这是因为在函数调用时,参数自左向右逐个匹配,当实参和形参个数不一致时,只有这样才不会产生二义性。

习惯上,缺省参数在公共头文件包含的函数声明中指定,不要函数的定义中指定。

如果在函数的定义中指定缺省参数值,在公共头文件包含的函数声明中不能再次指定缺省参数值。

缺省实参不一定必须是表达式,可以是任意表达式。

当缺省实参是一个表达式时,在函数被调用时该表达式被求值。

C语言不支持。

函数重载

C语言实现int,double,char类型的比较大小函数。

这些函数都执行了相同的一般动作;都返回两个形参中的最大值;从用户的角度来看,只有一种操做,就是得到两个数据中的最大值。

这种词汇上的复杂性不是“判断参数中的最大值”问题本身固有的,而是反映了程序设计环境的一种局限性;在同一个域中出现的名字必须指向一个唯实体(函数体)。

这种复杂性给程序员带来了一个实际问题,他们必须记住或查找每一个函数名字。

函数重载把程序员从这种词汇复杂性中解放出来。

函数重载的概念:

在C++中可以为两个或两个以上的函数提供相同的函数名称,只需要参数类型不同,或参数类型相同而参数的个数不同,称为函数重载。

判断函数重载的规则

1.如果两个函数的参数表相同,但是返回类型不同,就会被标记为编译错误:函数的重复声明。

2.参数表的比较过程与形参名无关。

3.如果在两个函数的参数表中,只有缺省实参不同,则第二个声明被视为第一个的重复声明。

4.typedef名为现有的数据类型提供了一个替换名,它并没有创建一个新类型,因此,如果两个函数参数表的区别只在于一个使用了typedef,而另一个使用了与typedef相应的类型。则该参数表被视为相同的参数列表。

5.当一个形参类型有const或volatile修饰时,如果形参时按值传递方式定义,在识别函数声明是否相同时,并不考虑const和volatile修饰符。

6.当一个形参类型有const或volatile修饰时,如果形参定义指针或引用时,在识别函数声明是否相同时,就要考虑const和volatile修饰符。

7.注意函数调用的二义性;如果在两个函数的参数表中,形参类型相同,而形参个数不同,形参默认值将会影响函数的重载。

函数重载解析的步骤如下

1.确定函数调用考虑的重载函数的集合,确定函数调用中实参表的属性。

2.从重载函数集合中选择函数,该函数可以在(给出实参个数和类型)的情况下可以调用函数。

3.选择与调用最匹配的函数。

名字粉碎(名字修饰)

“c”或者“c++”函数在内部(编译和链接)通过修饰名识别。修饰名时编译器在编译函数定义或者原型时生成的字符串。

修饰名由函数名,类名,调用约定,返回值类型,参数表共同决定。

调用约定:

_stdcall时Pascal程序的缺省调用方式,通常用于Win32 Api中,函数采用从右到左的压栈方式,自己退出时清空堆栈。

C调用约定(即_cdecl关键字说明)按从右至左的顺序压参数入栈,由调用者把参数弹出栈。对于传送参数的内存栈时由调用者维护的(正因如此,实现可变参数的函数只能使用该调用约定)。

_fastcall调用约定是“人“如其名,它的主要特点就是快,因为它是通过寄存器来参送参数的(实际上,它用ECX和EDX传送前两个双字(DWORD)或更小的参数,剩下的参数仍旧自右向左压栈传送,被调用的函数在返回值前清理传送参数的内存栈),在函数名修饰约定方面,它和前两者均不同。

thiscall仅仅应用与”C++“类的成员函数。this指针存放于ECX寄存器,参数从右到左压。thiscall不是关键词,因此不能被程序员指定。

在c/c++中,一个程序要运行起来,需要经过:预编译(预处理),编译,汇编,链接。Name Mangling是一种在编译过程中,将函数名,变量名的名字重新命名的机制。

C语言编译时函数名修饰约定规则

C语言的名字修饰规则非常简单,_cdecl是C/C++的缺省调用方式,调用约定函数名字前面添加了下划线前缀。

_stdcall调用约定在输出函数名前加上一个下划线前缀,后面加上一个”@”符号和其参数的字节数。

_fastcall调用约定在输出函数名前加上一个“@”符号,函数名后面也是一个“@”符号和其参数的字节数。

C++编译时函数名修饰约定规则:

_cddcl调用约定:

1.以“?”表示函数名的开始,后跟函数名;

2.函数名后以“@@YA”表示参数表的开始,后更参数表;

3.参数表以代号表示:

X -- void, D -- char, E -- unsigned char, F -- short, H -- int, I -- unsiigned int,

J -- long, K --unsigned long, M -- double, _N -- bool, ......

PA -- 表示指针,后面的代号表明指针类型,如果相同类型的指针连续出现,以“0”代替,一个“0”代表一次重复;

4.参数表的第一项为该函数的返回值类型,其后依次为参数的数据类型,指针标识在其所致数据类型前;

5.参数表后以“@Z”标识整个名字的结束,如果该函数无参数,则以“Z”标识结束。

函数模板

为了代码重用,代码就必须时通用的;通用的代码就必须不受数据类型的限制。那么我们可以把数据类型改成一个设计参数。这种类型的程序设计称为参数化程序设计。

软件模块由模板构造。包括函数模板和类模板。

函数模板可以用来创建一个通用功能的函数,以支持多种不同形参,简化重载函数的设计。

<模板参数表>尖括号中不能为空,参数可以有多个,用逗号分开。模板参数主要是模板类型参数。

模板类型参数代表一种类型,由关键字class或typename(建议使用typename)后加一个标识符构成,在这里两个关键字意义相同,它们表示后面的参数名代表一个潜在的内置或用户设计的类型。

函数模板根据一组实际类型或值构造出独立的函数的过程通常是隐式发生的,称为模板实参推演。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值