几种函数的调用方式

上传人:ji****72 文档编号:37609701 上传时间:2018-04-19 格式:DOCX 页数:44 大小:228.06KB
返回 下载 相关 举报
几种函数的调用方式_第1页
第1页 / 共44页
几种函数的调用方式_第2页
第2页 / 共44页
几种函数的调用方式_第3页
第3页 / 共44页
几种函数的调用方式_第4页
第4页 / 共44页
几种函数的调用方式_第5页
第5页 / 共44页
点击查看更多>>
资源描述

《几种函数的调用方式》由会员分享,可在线阅读,更多相关《几种函数的调用方式(44页珍藏版)》请在金锄头文库上搜索。

1、1几几种种函函数数的的调调用用方方式式_cdecl 是 C DECLaration 的缩写(declaration,声明),表示 C 语言默认的 函数调用方法:所有参数从右到左依次入栈,这些参数由调用者清除,称为手动清栈。 被调用函数不需要求调用者传递多少参数,调用者传递过多或者过少的参数,甚至完全 不同的参数都不会产生编译阶段的错误。 _stdcall 是 StandardCall 的缩写,是 C+的标准调用方式:所有参数从右到左 依次入栈,如果是调用类成员的话,最后一个入栈的是this 指针。这些堆栈中的参 数由被调用的函数在返回后清除,使用的指令是 retnX,X 表示参数占用的字节数,

2、 CPU 在 ret 之后自动弹出 X 个字节的堆栈空间。称为自动清栈。函数在编译的时候就 必须确定参数个数,并且调用者必须严格的控制参数的生成,不能多,不能少,否则返 回后会出错。 PASCAL 是 Pascal 语言的函数调用方式,也可以在C/C+中使用,参数压栈顺序 与前两者相反。返回时的清栈方式忘记了 _fastcall 是编译器指定的快速调用方式。由于大多数的函数参数个数很少, 使用堆栈传递比较费时。因此 _fastcall 通常规定将前两个(或若干个)参数由寄存 器传递,其余参数还是通过堆栈传递。不同编译器编译的程序规定的寄存器不同。返回 方式和_stdcall 相当。 _this

3、call 是为了解决类成员调用中 this 指针传递而规定的。 _thiscall 要求 把 this 指针放在特定寄存器中,该寄存器由编译器决定。VC 使用 ecx,Borland 的 C+编译器使用 eax。返回方式和 _stdcall 相当。 _fastcall 和 _thiscall 涉及的寄存器由编译器决定,因此不能用作跨编译器的 接口。所以 Windows 上的 COM 对象接口都定义为 _stdcall 调用方式。 C 中不加说明默认函数为 _cdecl 方式(C 中也只能用这种方式), C+也一 样,但是默认的调用方式可以在IDE 环境中设置。 带有可变参数的函数必须且只能使用

4、 _cdecl 方式,例如下面的函数 : int printf(char * fmtStr, .); int scanf(char * fmtStr, .); */几种调用约定的区别 编辑本段几种调用约定的区别 _cdecl _fastcall 与 _stdcall,三者都是调用约定 (Calling convention), 它决定以下内容: 1)函数参数的压栈顺序, 2)由调用者还是被调用者把参数弹出栈, 3)以及产生函数修饰名的方法。 1、_stdcall 调用约定:函数的参数自右向左通过栈传递,被调用的函数在返回 前清理传送参数的内存栈, 2、_cdecl 是 C 和 C程序的缺省调用

5、方式。每一个调用它的函数都包含清空堆 栈的代码,所以产生的可执行文件大小会比调用_stdcall 函数的大。函数采用从右 到左的压栈方式。注意:对于可变参数的成员函数,始终使用_cdecl 的转换方式。 3、_fastcall 调用约定:它是通过寄存器来传送参数的(实际上,它用ECX 和 EDX 传送前两个双字( DWORD)或更小的参数,剩下的参数仍旧自右向左压栈传送, 被调用的函数在返回前清理传送参数的内存栈)。 4、thiscall 仅仅应用于 “C+“成员函数。 this 指针存放于 CX 寄存器,参数从右 到左压。thiscall 不是关键词,因此不能被程序员指定。 25、naked

6、call 采用 1-4 的调用约定时,如果必要的话,进入函数时编译器会产生 代码来保存 ESI,EDI,EBX,EBP 寄存器,退出函数时则产生代码恢复这些寄存器的内 容。naked call 不产生这样的代码。 naked call 不是类型修饰符,故必须和 _declspec 共同使用。 编辑本段名字修饰约定 1、修饰名(Decoration name):“C“或者“C+“函数在内部(编译和链接)通过修 饰名识别 2、C 编译时函数名修饰约定规则: _stdcall 调用约定在输出函数名前加上一个下划线前缀,后面加上一个 “符号和其参数的字节数,格式为 _functionnamenumbe

7、r,例如 :function(int a, int b),其修饰名为: _function8 _cdecl 调用约定仅在输出函数名前加上一个下划线前缀,格式为 _functionname。 _fastcall 调用约定在输出函数名前加上一个 “符号,后面也是一个 “ 符号和其参数的字节数,格式为 functionnamenumber。 编辑本段设置方法 1 可以直接在代码中写 _cdecl 等调用约定 2 在 MS-VC+6.0 中,调用约定也可以通过工程设置: Setting.C/C+ Code Generation 项进行选择,缺省状态为 _cdecl。名字修饰约定。静态函数静态函数函数调

8、用的结果不会访问或者修改任何对象(非 static)数据成员,这样的成员声明为静态成员函数比较好。且如果 static int func(.)不是出现在类中,则它不是一个静态成员函数,只是一个普通的全局函数,只不过由于 static 的限制,它只能在文件所在的编译单位内使用,不能在其它编译单位内使用。静态成员函数的声明除了在类体的函数声明前加上关键字static,以及不能声明为 const 或者 volatile 之外,与非静态成员函数相同。出现在类体之外的函数定义不能制定关键字 static。 静态成员函数没有 this 指针。 = Static 关键字 在类中,用 static 声明的成员

9、变量为静态成员变量,它为该类的公用变量,在第一次使用时被初始化,对于该类的所有对象来说,static 成员变量只有一份。 用 static 声明的方法是静态方法,在调用该方法时,不会将对象的引用传递给它,所以在 static 方法中不可访问非 static 的成员 #静态方法不再是针对于某个对象调用,所以不能访问非静态成员 可以通过对象引用或类名(不需要实例化)访问静态成员 java: public class Cat 3 private static int sid = 0; private String name; int id; Cat(String name) = name; id =

10、 sid+; public void info() System.out.println (“My name is “+name+“ No.“+id); public static void main(String arg) Cat.sid = 100; Cat mimi = new Cat(“mimi“); mimi.sid = 2000; Cat pipi = new Cat(“pipi“); = 如果某些成员函数只访问静态数据成员,那么最好把他们声明为静态的成员函数,因为这样不需要特定的对象就可以访问这些成员变量了。 虚函数目录定义 作用 示例 1.其他信息 c+的虚函数 1.最后的说明

11、:定义 4作用 示例 1.其他信息 c+的虚函数 1.最后的说明:展开编辑本段定定义义虚函数必须是基类的非 静态成员函数,其访问权限可以是 protected 或 public,在基类的类定义中定义虚函数的一般形式: virtual 函数返回值类型 虚函数名(形参表) 函数体 编辑本段作作用用虚函数的作用是实现 动态联编,也就是在程序的运行阶段动态地选择合适的成员函数,在定义了虚函数后,可以在基类的派生类中对虚函数重新定义,在派生类中重新定义的函数应与虚函数具有相同的形参个数和形参类型。以实现统一的接口,不同定义过程。如果在派生类中没有对虚函数重新定义,则它继承其基类的虚函数。 当程序发现虚函

12、数名前的关键字virtual 后,会自动将其作为动态联编处理,即在程序运行时动态地选择合适的成员函数。 (2010.10.28 注:下行语义容易使人产生理解上的偏差,实际效果应为: 如存在:Base - Derive1 - Derive2 及它们所拥有的虚函数 func() 则在访问派生类 Derive1 的实例时,使用其基类 Base 及本身类型 Derive1,或被静态转换的后续派生类 Derive2 的指针或引用,均可访问到 Derive1 所实现的 func()。) 动态联编规定,只能通过指向基类的指针或基类对象的引用来调用虚函数,其格式:指向基类的指针变量名 -虚函数名(实参表) 或

13、 基类对象的引用名 . 虚函数名(实参表) 虚函数是 C+多态的一种表现 例如:子类继承了父类的一个函数(方法),而我们把父类的指针指向子类,则必须把父类的该函数(方法)设为virtual(虚函数)。 使用虚函数,我们可以灵活的进行动态绑定,当然是以一定的开销为代价。 如果父类的函数(方法)根本没有必要或者无法实现,完全要依赖子类去实现的话,可以把此函数(方法)设为 virtual 函数名=0 我们把这样的函数(方法)称为纯虚函数。 如果一个类包含了纯虚函数,称此类为抽象类 。 编辑本段示示例例5虚虚函函数数的的实实例例#include class Cshape public: void Se

14、tColor( int color) m_nColor=color; void virtual Display( void) coutDisplay( ); 本程序运行结果: Cshape Cellipse Ctriangle Crectangle 6条条件件所以,从以上程序分析,实现动态联编需要三个条件: 1、 必须把动态联编的行为定义为类的虚函数。 2、 类之间存在子类型关系,一般表现为一个类从另一个类公有派生而来。 3、 必须先使用基类指针指向子类型的对象,然后直接或者间接使用基类指针调用虚函数。 编辑本段其其他他信信息息定义虚函数的限制: (1)非类的成员函数不能定义为虚函数,类的成员

15、函数中静态成员函数和 构造函数也不能定义为虚函数,但可以将析构函数定义为虚函数。实际上,优秀的程序员常常把基类的析构函数定义为虚函数。因为,将基类的析构函数定义为虚函数后,当利用 delete 删除一个指向派生类定义的对象指针时,系统会调用相应的类的析构函数。而不将析构函数定义为虚函数时,只调用基类的析构函数。 (2)只需要在声明函数的类体中使用关键字 “virtual”将函数声明为虚函数,而定义函数时不需要使用关键字 “virtual”。 (3)当将基类中的某一成员函数声明为虚函数后,派生类中的同名函数自动成为虚函数。 (4)如果声明了某个成员函数为虚函数,则在该类中不能出现和这个成员函数同名并且返回值、参数个数、类型都相同的非虚函数。在以该类为基类的派生类中,也不能出现这种同名函数。 虚函数联系到 多态,多态联系到继承。所以本文中都是在继承层次上做文章。没了继承,什么都没得谈。 编辑本段c c+ + +的的虚虚函函数数下面是对 C+的虚函数这玩意儿的理解。 7一一, 什什么么是是虚虚函函数数(如果不知道虚函数为何物,但又急切的想知道,那你就应该从这里开始) 简单地说,那些被 virtual 关键字修饰的成员函数,就是虚函数。虚函数的作用,用

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 行业资料 > 其它行业文档

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号