您的位置:首页 > 编程语言 > Java开发

F#入门-第四章 面向对象-第五节 继承

2010-09-21 13:03 183 查看
应该使用继承的场合
    继承是指以现有的类(父类)为基础,定义新类(子类)。子类继承父类的所有功能,可以对父类的功能进行改写,可以追加新的功能。继承的功用是十分强大的,但是如果使用不得当的话,会使程序设计变得非常奇怪,所以首先让我们来看应该使用继承的正确场合。

    通过继承,子类继承了父类的全部功能,也就是说,子类可以说是父类的一种,这里是重点,一般说来只有当“子类就是父类的一种”这种关系成立的时候,才应该使用继承。

    拿汽车来举例说明,“公共汽车是汽车的一种“,“小轿车是汽车的一种“,这种说法是正确的,所以公共汽车类或小轿车类继承汽车类是不会有什么问题的。但是,“轮胎是汽车的一种“这种说法是错误的,所以轮胎类继承汽车类是不正确的。

    这种“A是B的一种”的关系在面向对象的专门术语种叫做“is-a关系”,谈到继承的原则时,只有“is-a关系”成立时才应该进行继承。同时,“A具有B"这种关系叫做"has-a关系"。上例中,因为可以说“汽车具有轮胎”,所以汽车和轮胎的关系是"has-a关系",当这种"has-a关系"成立时不应该使用继承,而应该使用聚合或复合的技术,这样才能很好地进行程序设计。关于聚合与复合,在后文详述。

继承
  F#的继承与Java和C#语言中的继承一样,只支持单父类(与接口)继承。这恐怕是因为多父类继承(多重继承)会产生譬如菱形继承等各种各样问题的缘故。

    类的继承的书写方法为在class关键字后加inherit关键字,然后指定父类。

    首先,创建父类。

准备:父类的定义
type Mouse = class

    val name : string

    new (n) = {name = n}

    end;;

let hatuka = new Mouse("Hatuka nezumi");;

    上例中创建了老鼠类。就象例子中记述的那样,该类只具有名字。接着,我们创建一个继承该类并具有口袋的老鼠类。

类的继承
type PocketMouse = class inherit Mouse

    val pocket : string

    new (namae,contents) = {inherit Mouse(namae);pocket = contents;}

    end;;

let dora = new PocketMouse("doraemon","4jigen pocket");;

let pika = new PocketMouse("pikachu","denki bukuro");;

    上例中创建了继承mouse类的pocketmouse类。pocketmouse类继承了mouse类的全部成员,所以也具有没有特别声明的name字段。

    class inherit mouse的部分为实现继承的部分,利用该表达式声明mouse类的继承。同时,在构造器的初始化的位置,调用父类的构造器,调用时使用inherit关键字。

    创建类时,知道父类与子类的构造器的调用顺序是十分有用的。接下来的例子中,确认构造器的调用顺序。

构造器的调用顺序
type Mouse = class

    val name : string

    new (n) = {name = n} then System.Console.WriteLine("base class constructor called")

    end;;

type PocketMouse = class inherit Mouse

    val pocket : string

    new (namae,contents) = {inherit Mouse(namae);pocket = contents;}

    then System.Console.WriteLine("sub class constructor called");

    end;;

let dora = new PocketMouse("doraemon","4jigen pocket");;

    正如下面执行结果所示,首先调用基本类的构造器。

执行结果
base class constructor called

sub class constructor called

按任何键继续 . . .

    另外,在子类的构造器的初始化的部分,不想显式调用父类的构造器的时候,可以使用()作为参数来调用构造器。

简化了初始化的构造器
type Mouse = class

    val name : string

    new () = {name = "nezumi"} then System.Console.WriteLine("base class constructor called")

    end;;

type PocketMouse = class inherit Mouse

    val pocket : string

    new (contents) = {pocket = contents;}

    then System.Console.WriteLine("sub class constructor called");

    end;;

let dora = new PocketMouse("4jigen pocket");;

    其执行结果与前面的执行结果相同。

执行结果
base class constructor called

sub class constructor called

按任何键继续 . . .

    正如下例所示,当没有接受()作为参数的构造器时,会产生编译错误。

没有接受()作为参数的构造器时会产生编译错误
type Mouse = class

    val name : string

    new (n) = {name = n} then System.Console.WriteLine("base class constructor called") 

    end;;

type PocketMouse = class inherit Mouse

    val pocket : string

    new (contents) = {pocket = contents;}

    then System.Console.WriteLine("sub class constructor called");

    end;;

let dora = new PocketMouse("4jigen pocket");;

    最后,使用默认的构造器,书写的程序如下所示。

默认的构造器
type Mouse(n) = class

    member x.name = n : string

    end;;

type PocketMouse(n,contents) = class inherit Mouse(n)

    member x.pocket = contents : string

    end;;

let dora = new PocketMouse("doraemon","4jigen pocket");;

    这种情况下,调用父类的构造器时的参数是在用inherit关键字声明父类时一起指定的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息