热度 2||
12、基类和子类
一个基类可以是另一个基类的子类,这样便形成了复杂的继承结构。出现了类的层次。
一个基类派出一个子类A,该子类又做了另一个子类B的基类。则原来的基类为子类B的间接基类。
子类将其自身与基类区别开来的方法是添加数据成员和成员函数
如何定义子类呢?
Type 学生
……
End type
Type 大学生 extends 学生
……
End type
注意:关键词extends是复数形式
目前到freebasic1.0为止,FB的子类只能以public方式继承自基类。(也许是我不知道如何使用protected方式继承)
Public方式的特点:
14、基类和子类的重名成员
子类定义了与基数同名的成员,在子类中访问同名成员时,自动隐藏基类的同名成员
在子类中使用基类的同名成员,可以显式使用基类名.成员或base.成员
15、基类和子类的构造函数
一个子类对象也属于其基类,因此当程序创建一个子类对象时,系统首先自动创建一个基类的对象。
在调用子类的构造函数构建子类对象时,系统首先调用基类的构造函数构建基类对象,当子类对象的生存期结束时,首先调用子类的析构函数,然后调用基类的析构函数
基类构造函数的调用方式:
隐式调用和显式调用两种方式:
(1)隐式方式是指在子类的构造函数中不指定对对应的基类的构造函数,调用的是基类的默认构造函 数即含有缺省参数值和不带有参数的构造函数)(2)显式方式是指在子类的构造函数中指定要调用的基类构造函数。并将子类构造函数的部分参数值传递给基类构造函数(注:除非基类有默认的构造函数,否则必须采用显式调用方式)
16、多态性和虚函数
多态性是面向对象程序设计的一个重要特征,它主要表现在函数调用时实现“一种接口,多种方法”。
编译时多态性和运行时多态性。
编译时多态性:在函数名或运算符相同的情况下,编译器在编译阶段就能能够根据函数参数类型的
不同来确定要调用的函数—通过重载实现。
运行时多态性:在函数名、函数参数和返回类型都桢同的情况下,只能在程序 运行时
才能确定要调用的函数——通过虚函数实现。
17、虚函数virtual
(1)、虚函数的定义
定义:在某基类中声明为 virtual 并在一个或多个子类中被重新定义的成员函数。
语法:virtual Function[或sub] 函数名(参数表)
End function
用途:
实现多态性,通过指向子类的基类指针,访问子类中同名覆盖成员函数
虚函数必须是基类的非静态成员函数,其访问权限可以是protected或public。
定义为virtual的函数是基类期待子类重新定义的,基类希望子类继承的函数不能定义为虚函数。
(2)、虚函数的作用
虚函数的作用是实现动态联编,也就是在程序的运行阶段动态地选择合适的成员函数,在定义了虚函
数后,可以在基类的子类中对虚函数重新定义,在子类中重新定义的函数应与虚函数具有相同的形参
个数和形参类型。以实现统一的接口,不同定义过程。如果在子类中没有对虚函数重新定义,则它
继承其基类的虚函数。
当程序发现虚函数名前的关键字virtual后,会自动将其作为动态联编处理,即在程序运行时动态地选择
合适的成员函数。虚函数是FreeBasic多态的一种表现。
使用虚函数,我们可以灵活的进行动态绑定,当然是以一定的开销为代价。如果父类的函数(方法)
根本没有必要或者无法实现,完全要依赖子类去实现的话,可以把此函数(方法)设为virtual 函数名=0
我们把这样的函数(方法)称为纯虚函数,如果一个类包含了纯虚函数,称此类为抽象类。
我们只需在把基类的成员函数设为virtual,其子类的相应的函数也会自动变为虚函数。
(3)虚函数的动态绑定过程
表面点来说,虚函数是根据调用它的指针或引用所指向或绑定的对象的类型来调用绑定或指向的类型
所定义的虚函数版本。
由于类中有虚函数存在,所以编译器就会为这个类插入一段你不知道的数据,并为它创建一个表。那段数据叫做vptr指针,指向那个表。那个表叫做vtbl,每个类都有自己的vtbl,vtbl的作用就是保存自定义为virtual的函数是基类期待子类重新定义的,基类希望子类继承的函数不能定义为虚函数。基类中虚函数的地址,我们可以把vtbl形象地看成一个数组,这个数组的每个元素存放的就是虚函数的地址。
调用虚函数时,首先是取出vptr的值,这个值就是vtbl的地址,再根据这个值来到vtbl这里,取出vtbl中相应的slot里的值,这个值就是所在调用的虚函数的地址了,最后调用这个函数。现在我们可以看出来了,只要vptr不同,指向的vtbl就不同,而不同的vtbl里装着对应类的虚函数地址,所以这样虚函数就可以完成它的任务。
(4)纯虚函数
在基类中不能对虚函数给出有意义的实现,而把它声明为纯虚函数,它的实现留给该基类的子类去做。这就是纯虚函数的作用。
17、函数重载
函数重载:是指一组功能类似但函数参数类型(或个数)不同的函数可以共用一个函数名。
当FB编译器遇到重载函数的调用语句时,它能够根据不同的参数类型或不同的参数个数选择一个合适的函数。
不能利用函数返回类型的不同进行函数重载。因为在没有确定调用的是哪个函数之前,不知道函数的返回类型。
同样,不能利用引用进行函数重载。
一般函数的重载使FB程序具有更好的可扩充性。此外。类的成员函数也可以重载,特别是构造函数的重载给FB程序设计带来很大的灵活性。
如何区别重载、重写(覆盖)和隐藏?
(1).重载:重载从overload翻译过来,是指同一可访问区内被声明的几个具有不同参数列(参数的类型,个数,顺序不同)的同名函数,根据参数列表确定调用哪个函数,重载不关心函数返回类型。
示例代码如下:
Type A
public:
sub test( I as integer);
sub test( I as double);
sub test( I as integer, j as double);
sub test(I as sing, j as long);
function test(I as integer) as long; ‘错误,非重载
end type
前四个互为重载函数,最后一个和第一个不是重载函数。
(2).隐藏:隐藏是指子类的函数屏蔽了与其同名的基类函数。注意只要同名函数,不管参数列表是否相同,基类函数都会被隐藏。
(3).重写:重写翻译自override,也翻译成覆盖(更好一点),是指子类中存在重新定义的函数。其函数名,参数列表,返回值类型,所有都必须同基类中被重写的函数一致。只有函数体不同,子类调用时会调用子类的重写函数,不会调用被重写函数。重写的基类中被重写的函数必须有virtual修饰。
Type A
public:
virtual Function fun3( I as long) as long{
return i+1
end function
end type
type B extends A ‘B从A继承
public:
‘重写
virtual Function fun3( I as long) as long
return i*3
end function
end type
重载和重写的区别:
(1)范围区别:重写和被重写的函数在不同的类中,重载和被重载的函数在同一类中。
(2)参数区别:重写与被重写的函数参数列表一定相同,重载和被重载的函数参数列表一定不同。
(3)virtual的区别:重写的基类必须要有virtual修饰,重载函数和被重载函数可以被virtual修饰,也可以没有。
隐藏和重写,重载的区别:
(1)与重载范围不同:隐藏函数和被隐藏函数在不同类中。
(2)参数的区别:隐藏函数和被隐藏函数参数列表可以相同,也可以不同,但函数名一定同;当参数不同时,无论基类中的函数是否被virtual修饰,基类函数都是被隐藏,而不是被重写。|站长邮箱|小黑屋|手机版|Office中国/Access中国 ( 粤ICP备10043721号-1 )
GMT+8, 2024-11-25 04:33 , Processed in 0.066000 second(s), 18 queries .
Powered by Discuz! X3.3
© 2001-2017 Comsenz Inc.