• <menu id="w2i4a"></menu>
  • logo Swift編程語(yǔ)言中文教程

    文檔首頁(yè)>>Swift編程語(yǔ)言中文教程>>Swift編程語(yǔ)言中文教程(十三):Swift繼承的用法

    Swift編程語(yǔ)言中文教程(十三):Swift繼承的用法


    一個(gè)類(lèi)可以繼承另一個(gè)類(lèi)的方法,屬性和其它特性。當(dāng)一個(gè)類(lèi)繼承其它類(lèi),繼承類(lèi)叫子類(lèi),被繼承類(lèi)叫超類(lèi)(或父類(lèi))。在Swift中,繼承是區(qū)分「類(lèi)」與其它類(lèi)型的一個(gè)基本特征。

    在Swift中,類(lèi)可以調(diào)用和訪問(wèn)超類(lèi)的方法,屬性和下標(biāo),并且可以重寫(xiě)(override)這些方法,屬性和下標(biāo)來(lái)優(yōu)化或修改它們的行為。Swift會(huì)檢查你的重寫(xiě)定義在超類(lèi)中是否有匹配的定義,以此確保你的重寫(xiě)行為是正確的。

    可以為類(lèi)中繼承來(lái)的屬性添加屬性觀察器(property observer),這樣一來(lái),當(dāng)屬性值改變時(shí),類(lèi)就會(huì)被通知到??梢詾槿魏螌傩蕴砑訉傩杂^察器,無(wú)論它原本被定義為存儲(chǔ)型屬性(stored property)還是計(jì)算型屬性(computed property)。

    定義一個(gè)基類(lèi)

    不繼承于其它類(lèi)的類(lèi),稱(chēng)之為基類(lèi)。

    注意:Swift中的類(lèi)并不是從一個(gè)通用的基類(lèi)繼承而來(lái)。如果你不為你定義的類(lèi)指定一個(gè)超類(lèi)的話,這個(gè)類(lèi)就自動(dòng)成為基類(lèi)。

    下面的例子定義了一個(gè)叫Vehicle的基類(lèi)。這個(gè)基類(lèi)聲明了兩個(gè)對(duì)所有車(chē)輛都通用的屬性(numberOfWheels和maxPassengers)。這些屬性在description方法中使用,這個(gè)方法返回一個(gè)String類(lèi)型的,對(duì)車(chē)輛特征的描述:

    class Vehicle {
        var numberOfWheels: Int
        var maxPassengers: Int
        func description() -> String {
            return "\(numberOfWheels) wheels; up to \(maxPassengers) passengers"
        }
        init() {
            numberOfWheels = 0
            maxPassengers = 1
        }
    }

    Vehicle類(lèi)定義了初始化器(initializer)來(lái)設(shè)置屬性的值。初始化器會(huì)在構(gòu)造函數(shù)一節(jié)中詳細(xì)介紹,這里我們做一下簡(jiǎn)單介紹,以便于講解子類(lèi)中繼承來(lái)的屬性可以如何被修改。

    初始化器用于創(chuàng)建某個(gè)類(lèi)型的一個(gè)新實(shí)例。盡管初始化器并不是方法,但在語(yǔ)法上,兩者很相似。初始化器的工作是準(zhǔn)備新實(shí)例以供使用,并確保實(shí)例中的所有屬性都擁有有效的初始化值。

    初始化器的最簡(jiǎn)單形式就像一個(gè)沒(méi)有參數(shù)的實(shí)例方法,使用init關(guān)鍵字:

    init() {
        // perform some initialization here
    }

    如果要?jiǎng)?chuàng)建一個(gè)Vehicle類(lèi)的新實(shí)例,使用初始化器語(yǔ)法調(diào)用上面的初始化器,即類(lèi)名后面跟一個(gè)空的小括號(hào):

    let someVehicle = Vehicle()

    這個(gè)Vehicle類(lèi)的初始化器為任意的一輛車(chē)設(shè)置一些初始化屬性值(numberOfWheels = 0和maxPassengers = 1)。

    Vehicle類(lèi)定義了車(chē)輛的共同特性,但這個(gè)類(lèi)本身并沒(méi)太大用處。為了使它更為實(shí)用,你需要進(jìn)一步細(xì)化它來(lái)描述更具體的車(chē)輛。

    Subclassing(子類(lèi)化?待定)

    subclassing指的是在一個(gè)已有類(lèi)的基礎(chǔ)上創(chuàng)建一個(gè)新的類(lèi)。子類(lèi)繼承超類(lèi)的特性,并且你可以優(yōu)化或改變它。你還可以為子類(lèi)添加新的特性。

    為了指明某個(gè)類(lèi)的超類(lèi),將超類(lèi)名寫(xiě)在子類(lèi)名的后面,用冒號(hào)分隔:

    class SomeClass: SomeSuperclass {
        // class definition goes here
    }

    下一個(gè)例子,定義一個(gè)更具體的車(chē)輛類(lèi)叫Bicycle。這個(gè)新類(lèi)是在Vehicle類(lèi)的基礎(chǔ)上創(chuàng)建起來(lái)。因此你需要將Vehicle類(lèi)放在Bicycle類(lèi)后面,用冒號(hào)分隔。

    我們可以將這讀作:

    “定義一個(gè)新的類(lèi)叫Bicycle,它繼承了Vehicle的特性”;

    class Bicycle: Vehicle {
        init() {
            super.init()
            numberOfWheels = 2
        }
    }

    Bicycle是Vehicle的子類(lèi),Vehicle是Bicycle的超類(lèi)。新的Bicycle類(lèi)自動(dòng)獲得Vehicle類(lèi)的特性,比如maxPassengers和numberOfWheels屬性。你可以在子類(lèi)中定制這些特性,或添加新的特性來(lái)更好地描述Bicycle類(lèi)。

    Bicycle類(lèi)定義了一個(gè)初始化器來(lái)設(shè)置它定制的特性(自行車(chē)只有2個(gè)輪子)。Bicycle的初始化器調(diào)用了它父類(lèi)Vehicle的初始化器super.init(),以此確保在Bicycle類(lèi)試圖修改那些繼承來(lái)的屬性前,Vehicle類(lèi)已經(jīng)初始化過(guò)它們了。

    注意:不像Objective-C,在Swift中,初始化器默認(rèn)是不繼承的,見(jiàn)初始化器的繼承與重寫(xiě)

    Vehicle類(lèi)中maxPassengers的默認(rèn)值對(duì)自行車(chē)來(lái)說(shuō)已經(jīng)是正確的,因此在Bicycle的初始化器中并沒(méi)有改變它。而numberOfWheels原來(lái)的值對(duì)自行車(chē)來(lái)說(shuō)是不正確的,因此在初始化器中將它更改為2。

    Bicycle不僅可以繼承Vehicle的屬性,還可以繼承它的方法。如果你創(chuàng)建了一個(gè)Bicycle類(lèi)的實(shí)例,你就可以調(diào)用它繼承來(lái)的description方法,并且可以看到,它輸出的屬性值已經(jīng)發(fā)生了變化:

    let bicycle = Bicycle()
    println("Bicycle: \(bicycle.description())")
    // Bicycle: 2 wheels; up to 1 passengers

    子類(lèi)還可以繼續(xù)被其它類(lèi)繼承:

    class Tandem: Bicycle {
        init() {
            super.init()
            maxPassengers = 2
        }
    }

    上面的例子創(chuàng)建了Bicycle的一個(gè)子類(lèi):雙人自行車(chē)(tandem)。Tandem從Bicycle繼承了兩個(gè)屬性,而這兩個(gè)屬性是Bicycle從Vehicle繼承而來(lái)的。Tandem并不修改輪子的數(shù)量,因?yàn)樗允且惠v自行車(chē),有2個(gè)輪子。但它需要修改maxPassengers的值,因?yàn)殡p人自行車(chē)可以坐兩個(gè)人。

    注意:子類(lèi)只允許修改從超類(lèi)繼承來(lái)的變量屬性,而不能修改繼承來(lái)的常量屬性。

    創(chuàng)建一個(gè)Tandem類(lèi)的實(shí)例,打印它的描述,即可看到它的屬性已被更新:

    let tandem = Tandem()
    println("Tandem: \(tandem.description())")
    // Tandem: 2 wheels; up to 2 passengers

    注意,Tandem類(lèi)也繼承了description方法。一個(gè)類(lèi)的實(shí)例方法會(huì)被這個(gè)類(lèi)的所有子類(lèi)繼承。

    重寫(xiě)(Overriding)

    子類(lèi)可以為繼承來(lái)的實(shí)例方法(instance method),類(lèi)方法(class method),實(shí)例屬性(instance property),或下標(biāo)(subscript)提供自己定制的實(shí)現(xiàn)(implementation)。我們把這種行為叫重寫(xiě)(overriding)。

    如果要重寫(xiě)某個(gè)特性,你需要在重寫(xiě)定義的前面加上override關(guān)鍵字。這么做,你就表明了你是想提供一個(gè)重寫(xiě)版本,而非錯(cuò)誤地提供了一個(gè)相同的定義。意外的重寫(xiě)行為可能會(huì)導(dǎo)致不可預(yù)知的錯(cuò)誤,任何缺少override關(guān)鍵字的重寫(xiě)都會(huì)在編譯時(shí)被診斷為錯(cuò)誤。

    override關(guān)鍵字會(huì)提醒Swift編譯器去檢查該類(lèi)的超類(lèi)(或其中一個(gè)父類(lèi))是否有匹配重寫(xiě)版本的聲明。這個(gè)檢查可以確保你的重寫(xiě)定義是正確的。

    訪問(wèn)超類(lèi)的方法,屬性及下標(biāo)

    當(dāng)你在子類(lèi)中重寫(xiě)超類(lèi)的方法,屬性或下標(biāo)時(shí),有時(shí)在你的重寫(xiě)版本中使用已經(jīng)存在的超類(lèi)實(shí)現(xiàn)會(huì)大有裨益。比如,你可以優(yōu)化已有實(shí)現(xiàn)的行為,或在一個(gè)繼承來(lái)的變量中存儲(chǔ)一個(gè)修改過(guò)的值。

    在合適的地方,你可以通過(guò)使用super前綴來(lái)訪問(wèn)超類(lèi)版本的方法,屬性或下標(biāo):

    • 在方法someMethod的重寫(xiě)實(shí)現(xiàn)中,可以通過(guò)super.someMethod()來(lái)調(diào)用超類(lèi)版本的someMethod方法。
    • 在屬性someProperty的getter或setter的重寫(xiě)實(shí)現(xiàn)中,可以通過(guò)super.someProperty來(lái)訪問(wèn)超類(lèi)版本的someProperty屬性。
    • 在下標(biāo)的重寫(xiě)實(shí)現(xiàn)中,可以通過(guò)super[someIndex]來(lái)訪問(wèn)超類(lèi)版本中的相同下標(biāo)。

    重寫(xiě)方法

    在子類(lèi)中,你可以重寫(xiě)繼承來(lái)的實(shí)例方法或類(lèi)方法,提供一個(gè)定制或替代的方法實(shí)現(xiàn)。

    下面的例子定義了Vehicle的一個(gè)新的子類(lèi),叫Car,它重寫(xiě)了從Vehicle類(lèi)繼承來(lái)的'description'方法:

    class Car: Vehicle {
        var speed: Double = 0.0
        init() {
            super.init()
            maxPassengers = 5
            numberOfWheels = 4
        }
        override func description() -> String {
            return super.description() + "; "
                + "traveling at \(speed) mph"
        }
    }

    Car聲明了一個(gè)新的存儲(chǔ)型屬性speed,它是Double類(lèi)型的,默認(rèn)值是0.0,表示“時(shí)速是0英里”。'Car'有自己的初始化器,它將乘客的最大數(shù)量設(shè)為5,輪子數(shù)量設(shè)為4。

    Car重寫(xiě)了繼承來(lái)的description方法,它的聲明與Vehicle中的description方法一致,聲明前面加上了override關(guān)鍵字。

    Car中的description方法并非完全自定義,而是通過(guò)super.description使用了超類(lèi)Vehicle中的description方法,然后再追加一些額外的信息,比如汽車(chē)的當(dāng)前速度。

    如果你創(chuàng)建一個(gè)Car的新實(shí)例,并打印description方法的輸出,你就會(huì)發(fā)現(xiàn)描述信息已經(jīng)發(fā)生了改變:

    let car = Car()
    println("Car: \(car.description())")
    // Car: 4 wheels; up to 5 passengers; traveling at 0.0 mph

    重寫(xiě)屬性

    你可以重寫(xiě)繼承來(lái)的實(shí)例屬性或類(lèi)屬性,提供自己定制的getter和setter,或添加屬性觀察器使重寫(xiě)的屬性觀察屬性值什么時(shí)候發(fā)生改變。

    重寫(xiě)屬性的Getters和Setters

    你可以提供定制的getter(或setter)來(lái)重寫(xiě)任意繼承來(lái)的屬性,無(wú)論繼承來(lái)的屬性是存儲(chǔ)型的還是計(jì)算型的屬性。子類(lèi)并不知道繼承來(lái)的屬性是存儲(chǔ)型的還是計(jì)算型的,它只知道繼承來(lái)的屬性會(huì)有一個(gè)名字和類(lèi)型。你在重寫(xiě)一個(gè)屬性時(shí),必需將它的名字和類(lèi)型都寫(xiě)出來(lái)。這樣才能使編譯器去檢查你重寫(xiě)的屬性是與超類(lèi)中同名同類(lèi)型的屬性相匹配的。

    你可以將一個(gè)繼承來(lái)的只讀屬性重寫(xiě)為一個(gè)讀寫(xiě)屬性,只需要你在重寫(xiě)版本的屬性里提供getter和setter即可。但是,你不可以將一個(gè)繼承來(lái)的讀寫(xiě)屬性重寫(xiě)為一個(gè)只讀屬性。

    注意:如果你在重寫(xiě)屬性中提供了setter,那么你也一定要提供getter。如果你不想在重寫(xiě)版本中的getter里修改繼承來(lái)的屬性值,你可以直接返回super.someProperty來(lái)返回繼承來(lái)的值。正如下面的SpeedLimitedCar的例子所示。

    以下的例子定義了一個(gè)新類(lèi),叫SpeedLimitedCar,它是Car的子類(lèi)。類(lèi)SpeedLimitedCar表示安裝了限速裝置的車(chē),它的最高速度只能達(dá)到40mph。你可以通過(guò)重寫(xiě)繼承來(lái)的speed屬性來(lái)實(shí)現(xiàn)這個(gè)速度限制:

    class SpeedLimitedCar: Car {
        override var speed: Double  {
        get {
            return super.speed
        }
        set {
            super.speed = min(newValue, 40.0)
        }
        }
    }

    當(dāng)你設(shè)置一個(gè)SpeedLimitedCar實(shí)例的speed屬性時(shí),屬性setter的實(shí)現(xiàn)會(huì)去檢查新值與限制值40mph的大小,它會(huì)將超類(lèi)的speed設(shè)置為newValue和40.0中較小的那個(gè)。這兩個(gè)值哪個(gè)較小由min函數(shù)決定,它是Swift標(biāo)準(zhǔn)庫(kù)中的一個(gè)全局函數(shù)。min函數(shù)接收兩個(gè)或更多的數(shù),返回其中最小的那個(gè)。

    如果你嘗試將SpeedLimitedCar實(shí)例的speed屬性設(shè)置為一個(gè)大于40mph的數(shù),然后打印description函數(shù)的輸出,你會(huì)發(fā)現(xiàn)速度被限制在40mph:

    let limitedCar = SpeedLimitedCar()
    limitedCar.speed = 60.0
    println("SpeedLimitedCar: \(limitedCar.description())")
    // SpeedLimitedCar: 4 wheels; up to 5 passengers; traveling at 40.0 mph

    重寫(xiě)屬性觀察器(Property Observer)

    你可以在屬性重寫(xiě)中為一個(gè)繼承來(lái)的屬性添加屬性觀察器。這樣一來(lái),當(dāng)繼承來(lái)的屬性值發(fā)生改變時(shí),你就會(huì)被通知到,無(wú)論那個(gè)屬性原本是如何實(shí)現(xiàn)的。關(guān)于屬性觀察器的更多內(nèi)容,請(qǐng)看屬性觀察器。

    注意:你不可以為繼承來(lái)的常量存儲(chǔ)型屬性或繼承來(lái)的只讀計(jì)算型屬性添加屬性觀察器。這些屬性的值是不可以被設(shè)置的,所以,為它們提供willSet或didSet實(shí)現(xiàn)是不恰當(dāng)。此外還要注意,你不可以同時(shí)提供重寫(xiě)的setter和重寫(xiě)的屬性觀察器。如果你想觀察屬性值的變化,并且你已經(jīng)為那個(gè)屬性提供了定制的setter,那么你在setter中就可以觀察到任何值變化了。

    下面的例子定義了一個(gè)新類(lèi)叫AutomaticCar,它是Car的子類(lèi)。AutomaticCar表示自動(dòng)擋汽車(chē),它可以根據(jù)當(dāng)前的速度自動(dòng)選擇合適的擋位。AutomaticCar也提供了定制的description方法,可以輸出當(dāng)前擋位。

    class AutomaticCar: Car {
        var gear = 1
        override var speed: Double {
        didSet {
            gear = Int(speed / 10.0) + 1
        }
        }
        override func description() -> String {
            return super.description() + " in gear \(gear)"
        }
    }

    當(dāng)你設(shè)置AutomaticCar的speed屬性,屬性的didSet觀察器就會(huì)自動(dòng)地設(shè)置gear屬性,為新的速度選擇一個(gè)合適的擋位。具體來(lái)說(shuō)就是,屬性觀察器將新的速度值除以10,然后向下取得最接近的整數(shù)值,最后加1來(lái)得到檔位gear的值。例如,速度為10.0時(shí),擋位為1;速度為35.0時(shí),擋位為4:

    let automatic = AutomaticCar()
    automatic.speed = 35.0
    println("AutomaticCar: \(automatic.description())")
    // AutomaticCar: 4 wheels; up to 5 passengers; traveling at 35.0 mph in gear 4

    防止重寫(xiě)

    你可以通過(guò)把方法,屬性或下標(biāo)標(biāo)記為final來(lái)防止它們被重寫(xiě),只需要在聲明關(guān)鍵字前加上@final特性即可。(例如:@final var, @final func, @final class func, 以及 @final subscript)

    如果你重寫(xiě)了final方法,屬性或下標(biāo),在編譯時(shí)會(huì)報(bào)錯(cuò)。在擴(kuò)展中,你添加到類(lèi)里的方法,屬性或下標(biāo)也可以在擴(kuò)展的定義里標(biāo)記為final。

    你可以通過(guò)在關(guān)鍵字class前添加@final特性(@final class)來(lái)將整個(gè)類(lèi)標(biāo)記為final的,這樣的類(lèi)是不可被繼承的,否則會(huì)報(bào)編譯錯(cuò)誤。

    本文資源來(lái)自互聯(lián)網(wǎng),由本網(wǎng)整理編輯,供大家學(xué)習(xí)參考。因?yàn)榧夹g(shù)有限,可能會(huì)有不足及錯(cuò)誤,請(qǐng)大家指正。

    掃碼咨詢


    添加微信 立即咨詢

    電話咨詢

    客服熱線
    023-68661681

    TOP
    三级成人熟女影院,欧美午夜成人精品视频,亚洲国产成人乱色在线观看,色中色成人论坛 (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })();