虚函数和动态联编.ppt
《虚函数和动态联编.ppt》由会员分享,可在线阅读,更多相关《虚函数和动态联编.ppt(52页珍藏版)》请在得力文库 - 分享文档赚钱的网站上搜索。
1、虚函数虚函数多态性是面向对象设计语言的基多态性是面向对象设计语言的基本特征。本特征。l仅仅是将数据和函数捆绑在一起,进行类的封装,使用一些简单的继承,还不能算是真正应还不能算是真正应用了面向对象的设计思想用了面向对象的设计思想。l多态性是面向对象的精髓,也是难点。l在C+中,多态性是通过虚函数来实现的。l#include l lclass vehicleclass vehicleint wheels;float weight;public:void message(void)cout Vehicle messagen;class car:public vehicleclass car:publ
2、ic vehicleint passenger_load;public:void message(void)cout Car messagen;l lclass truck:public vehicleclass truck:public vehicleint passenger_load;float payload;public:int passengers(voidpassengers(void)return passenger_load;l lclass boat:public vehicleclass boat:public vehicleint passenger_load;publ
3、ic:int passengers(voidpassengers(void)return passenger_load;void message(void)cout message();/输出Vehicle messagedelete unicycle;lunicycle=new car;unicycle=new car;unicycle-message();/输出Vehicle messagel/-lsedan=(car*)unicycle;sedan=(car*)unicycle;sedan-message();/输出Car messagedelete sedan;l/-lsemi.mes
4、sagesemi.message();/();/输出输出Vehicle messageVehicle message?sailboat.message();/输出Boat message 指针的类型决定调用那一个成员指针的类型决定调用那一个成员函数函数l因为指针的类型决定调用那一个成员函数,所以,一个vehicle*调用vehicle成员函数,即使它指向派生类的对象。l同样,一个car*也调用car 的成员函数。l我们把这称为早期联编或静态联编,因为指针要调用那一个函数是在编译时就确定的。能不能通过该指针来调用派生类能不能通过该指针来调用派生类的成员函数呢?的成员函数呢?l那么,当vehicl
5、e*指向派生类对象时,我们能不能通过该指针来调用派生类的成员函数呢?l在C+中,我们是可以作到的,这要用到C+的多态特性多态特性。l也就是说,基类指针是调用基类的成员函数,还是调用派生类的成员函数,不是由指针的类型决定的,而是由指针指向的对象的类型由指针指向的对象的类型决定的 动态联编或迟后联编动态联编或迟后联编l多态也称为动态联编或迟后联编,因为到底调用哪一个函数,在编译时不能确定,而要推迟推迟到运行时确定。到运行时确定。l也就是说,要等到程序运行时,确定了指针所指向的对象的类型时,才能够确定。l在C+中,动态联编是通过虚函数虚函数来实现的。l函数调用是通过相应的函数名来实现的。l对于源程序
6、进行编译后,存放在内存中的可执行程序,存放在内存中的可执行程序,存放在内存中的可执行程序,存放在内存中的可执行程序,函数实际上是一段机器代码函数实际上是一段机器代码函数实际上是一段机器代码函数实际上是一段机器代码,它是通过首地址进行标识和调用的。例如,假定定义一个函数:void func()/;我们可以用下面的语句调用这个函数:func();/调用func函数l这是在源程序中调用函数的方法,它是用函数名函数名函数名函数名操作的。函数执行的原理函数执行的原理l我们看看在可执行程序中函数调用是怎么操作的,我们用汇编语言来说明,因为汇编语言和机器语言(计算机可以直接执行的语言)是一一对应的。在可执行
7、程序中,函数调用使用下面的方法:call call xxxxxxxxxx xxxxx代表存放函数代码内存空间的首地址。lcall是汇编语句中的一条指令,意思是调用一个函数。l实际操作过程是:保存当前地址、保护现场,跳转到跳转到跳转到跳转到xxxxxxxxxx地址执行地址执行地址执行地址执行。l正是基于这个原因,在C/C+中的函数名是一个指针,该指针指向该函数段代码在内存中的首地址。早期或静态联编的原理早期或静态联编的原理l如何将源程序中的函数调用和函数体(也就是在内存中该函数的机器代码)联系起来呢?l这件工作是由编译器和连接程序编译器和连接程序编译器和连接程序编译器和连接程序来完成的。l在C/
8、C+语言中,函数调用在程序运行之前程序运行之前程序运行之前程序运行之前就已经和函数体(函数的首地址)联系起来。l编译器把函数体翻译成机器代码,并记录了函数的首地址。l在对函数调用的源程序段进行编译的时候,编译器知道这个函数名的首地址在那里(它可以从生成的标识符表中查到这个函数名对应的首地址),l然后将这个首地址替换函数名将这个首地址替换函数名将这个首地址替换函数名将这个首地址替换函数名,一并翻译成机器码。l这种编译方法称为早期或静态联编。动态联编动态联编l那么,当vehicle*指向派生类对象时,我们能不能通过该指针来调用派生类的成员函数呢?l从这种编译方法来看,是不可能的。因为编译器只会寻找
9、vehicle*的成员函数。l如何实现这个功能:当用基类指针调用成员函数时,是调用基类的成员函数,还是调用派生类的成员函数,不由指针的类型决定,而由指针指向的对象的类型决定呢?l也就是说,如果基类指针指向基类对象,就调用基类的成如果基类指针指向基类对象,就调用基类的成如果基类指针指向基类对象,就调用基类的成如果基类指针指向基类对象,就调用基类的成员函数,如果基类指针指向派生类对象,就调用派生类的员函数,如果基类指针指向派生类对象,就调用派生类的员函数,如果基类指针指向派生类对象,就调用派生类的员函数,如果基类指针指向派生类对象,就调用派生类的成员函数成员函数成员函数成员函数。l这就要用到另外一
10、种方法,称为动态联编或迟后联编。到底调用哪一个函数,在编译时不能确定,而要推迟到运行时确定。l在C+中,动态联编是通过虚函数虚函数虚函数虚函数来实现的。下面我们先介绍虚函数,然后讨论动态联编实现的原理。vehiclel#include/如果定义了如果定义了vehicle类的对象,编译器为该对象分配类的对象,编译器为该对象分配8个字节的个字节的存储空间存储空间class vehicleint wheels;/占用占用4个字节个字节float weight;/占用占用4个字节个字节public:void message(void)cout Vehicle messagen;/该函数不在类中分配空间
11、,编译器另外分配空间给该函数,该函数不在类中分配空间,编译器另外分配空间给该函数,并把函数首并把函数首/地址记录到一个标识符表中地址记录到一个标识符表中;carl/如果定义了如果定义了car类的对象,编译器为该对象分配类的对象,编译器为该对象分配12个字节的存储个字节的存储空间空间class car:public vehicle/基类占用基类占用8个字节个字节int passenger_load;/占用占用4个字节个字节public:void message(void)cout Car messagen;/该函数不在类中分配空间,编译器另外分配空间给该函数,该函数不在类中分配空间,编译器另外分
12、配空间给该函数,并把函数首并把函数首/地址记录到标识符表中地址记录到标识符表中;truckl/如果定义了如果定义了truck类的对象,编译器为该对象分配类的对象,编译器为该对象分配16个字节的存个字节的存储空间储空间class truck:public vehicle/基类占用基类占用8个字节个字节int passenger_load;/占用占用4个字节个字节float payload;/占用占用4个字节个字节public:int passengers(void)return passenger_load;/该函数不在类中分配空间,编译器另外分配空间给该函数,该函数不在类中分配空间,编译器另外
13、分配空间给该函数,并把函数首并把函数首/地址记录到标识符表中地址记录到标识符表中;boatl/如果定义了如果定义了boat类的对象,编译器为该对象分配类的对象,编译器为该对象分配12个字节的存个字节的存储空间储空间class boat:public vehicle/基类占用基类占用8个字节个字节int passenger_load;/占用占用4个字节个字节public:int passengers(void)return passenger_load;void message(void)cout message();/输出Vehicle message/*当编译器编译到上面语句的时候,会参照该
14、对象指针所属的当编译器编译到上面语句的时候,会参照该对象指针所属的类名类名vehicle和函数名和函数名message去标识符表中查找该成员函数的首去标识符表中查找该成员函数的首地址,查找到地址,查找到vehicle类的成员函数类的成员函数message的首地址,并使用的首地址,并使用call xxxxx语句替换该函数调用语句。语句替换该函数调用语句。*/ldelete unicycle;unicycle=new car;unicycle-message();/输出Vehicle message/*当编译器编译到上面这句的时候,会参照该对象指针所属的当编译器编译到上面这句的时候,会参照该对象指
15、针所属的类名类名vehicle和函数名和函数名message去标识符表中查找该成员函数的首去标识符表中查找该成员函数的首地址,它查到的也是地址,它查到的也是vehicle类的成员函数类的成员函数message的首地址,然的首地址,然后使用后使用call xxxxx语句替换该函数调用语句。语句替换该函数调用语句。*/lsedan=(car*)unicycle;sedan-message();/输出Car message/*当编译器编译到上面这句的时候,会参照该对象指针所属的类当编译器编译到上面这句的时候,会参照该对象指针所属的类名名car和函数名和函数名message去标识符表中查找该成员函数的
16、首地址,去标识符表中查找该成员函数的首地址,它查到的是它查到的是car类的成员函数类的成员函数message的首地址,然后使用的首地址,然后使用call xxxxx语句替换该函数调用语句。语句替换该函数调用语句。*/delete sedan;semi.message();/输出Vehicle message/*当编译器编译到上面这句的时候,会参照该对象指针所属的类当编译器编译到上面这句的时候,会参照该对象指针所属的类名名car和函数名和函数名message去标识符表中查找该成员函数的首地址,去标识符表中查找该成员函数的首地址,在基类在基类vehicle中它查到了成员函数中它查到了成员函数mes
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 函数 动态
限制150内