Swift-繼承、構(gòu)造、類擴(kuò)展、重寫

一個(gè)類可以從另外一個(gè)類中繼承方法,屬性或者其它的一些特性。當(dāng)一個(gè)類繼承于另外一個(gè)類時(shí),這個(gè)繼承的類叫子類,被繼承的類叫父類。繼承是Swift中類區(qū)別于其它類型的一個(gè)基本特征。

Swift中的類可以調(diào)用父類的方法,使用父類的屬性和下標(biāo),還可以根據(jù)需要使用重寫方法或者屬性來重新定義和修改他們的一些特性。Swift可以幫助你檢查重寫的方法和父類的方法定義是相符的。

類還可以為它繼承的屬性添加觀察者,這樣可以能夠讓它在一個(gè)屬性變化的時(shí)候得到通知。屬性觀察者可以被添加給任何屬性,不管它之前是存儲屬性還是計(jì)算屬性。

1、定義一個(gè)基類

任何一個(gè)不繼承于其它類的類被稱作基類

注意:Swift的類不是從一個(gè)全局基類繼承而來。在你編寫代碼的時(shí),只要是在類的定義中沒有繼承自父類的類都是基類。

下面的例子定義了一個(gè)叫Vehicle的基類?;惏瑑蓚€(gè)所有交通工具通用的屬性numberOfWheels和maxPassengers。這兩個(gè)屬性被一個(gè)叫description的方法使用,通過返回一個(gè)String描述來作為這個(gè)交通工具的特征:

復(fù)制代碼代碼如下:

class Vehicle {

var numberOfWheels: Int

var maxPassengers: Int

func description() -> String {

return "\(numberOfWheels) wheels; up to \(maxPassengers) passengers"

}

init() {

numberOfWheels = 0

maxPassengers = 1

}

}

這個(gè)交通工具類Vehicle還定義了一個(gè)構(gòu)造函數(shù)來設(shè)置它的屬性。構(gòu)造函數(shù)更多的解釋在Initialization一章,但是為了說明子類如何修改繼承的屬性,這里需要簡要解釋一下什么叫構(gòu)造函數(shù)。

通過構(gòu)造函數(shù)可以創(chuàng)建一個(gè)類型的實(shí)例。盡管構(gòu)造函數(shù)不是方法,但是它們在編碼的時(shí)候使用了非常相似的語法。構(gòu)造函數(shù)通過確保所有實(shí)例的屬性都是有效的來創(chuàng)建一個(gè)新的實(shí)例。

構(gòu)造函數(shù)最簡單的形式是使用init關(guān)鍵詞的一個(gè)類似方法的函數(shù),并且沒有任何參數(shù):

復(fù)制代碼代碼如下:

init() {

// perform some initialization here

}

使用構(gòu)造函數(shù)語法TypeName和空的兩個(gè)小括號來完成一個(gè)Vehicle實(shí)例的創(chuàng)建:

復(fù)制代碼代碼如下:

let someVehicle = Vehicle()

Vehicle的構(gòu)造函數(shù)為屬性設(shè)置了一些初始值(numberOfWheels = 0 然后 maxPassengers = 1)。

Vehicle類定義的是一個(gè)通用的交通工具特性,它本身沒有太多意義,所以就需要沖定義它的一些屬性或者方法來讓它具有實(shí)際的意義。

2、產(chǎn)生子類

產(chǎn)生子類就是根據(jù)一個(gè)已有的類產(chǎn)生新類的過程。子類繼承了父類的一些可以修改的特性。還可以為子類添加一些新的特性。

為了表明一個(gè)類是繼承自一個(gè)父類,需要將父類的名稱寫在子類的后面,并且用冒號分隔:

復(fù)制代碼代碼如下:

class SomeClass: SomeSuperclass {

// class definition goes here

}

下面的例子定義了一種特定叫Bicycle的交通工具。這個(gè)新類是基于已有的類Vehicle產(chǎn)生的。書寫方式是在類名Bicycle后加冒號加父類Vehicle名。

可以理解為:

定義一個(gè)新的類叫Bicycle,它繼承了Vehicle的特性:

復(fù)制代碼代碼如下:

class Bicycle: Vehicle {

init() {

super.init()

numberOfWheels = 2

}

}

Bicycle是Vehicle的子類,Vehicle是Bicycle的父類。Bicycle類繼承了Vehicle所有的特征,比如maxPassengers和numberOfWheels屬性。你還可以為Bicycle類添加心的屬性。

Bicycle類也定義了構(gòu)造函數(shù),在這個(gè)構(gòu)造函數(shù)中調(diào)用了父類的構(gòu)造函數(shù)super.init(),這樣可以確保在Bicycle修改他們之前,父類已經(jīng)初始化了。

注意:跟Objective-C不同的是,Swift中的構(gòu)造函數(shù)沒有默認(rèn)繼承。更多信息可以參考Initializer Inheritance and Overriding這一章節(jié)。

maxPassengers屬性在繼承自父類的時(shí)候已經(jīng)被初始化了,對于Bicycle來說是正確的,因此不需要再做更改。然后numberOfWheels是不對的,所以被替換成了2.

不僅屬性是繼承于Vehicle的,Bicycle還繼承了父類的方法。如果你創(chuàng)建一個(gè)實(shí)例,然后調(diào)用了已經(jīng)繼承的description方法,可以得到該交通工具的描述并且看到它的屬性已經(jīng)被修改:

復(fù)制代碼代碼如下:

let bicycle = Bicycle()

println("Bicycle: \(bicycle.description())")

// Bicycle: 2 wheels; up to 1 passengers

子類本身也可以作為父類被再次繼承:

復(fù)制代碼代碼如下:

class Tandem: Bicycle {

init() {

super.init()

maxPassengers = 2

}

}

上面的例子創(chuàng)建了Bicycle的子類,叫做tandem,也就可以兩個(gè)人一起騎的自行車。所以Tandem沒有修改numberOfWheels屬性,只是更新了maxPassengers屬性。

注意:子類只能夠在構(gòu)造的時(shí)候修改變量的屬性,不能修改常量的屬性。

創(chuàng)建一個(gè)Tandem的實(shí)例,然后調(diào)用description方法檢查屬性是否被正確修改:

復(fù)制代碼代碼如下:

let tandem = Tandem()

println("Tandem: \(tandem.description())")

// Tandem: 2 wheels; up to 2 passengers

注意到description方法也被Tandem繼承了。

3、重寫方法

子類可以提供由父類繼承來的實(shí)例方法,類方法,實(shí)例屬性或者下標(biāo)的個(gè)性化實(shí)現(xiàn)。這個(gè)特性被稱為重寫。

重寫一個(gè)由繼承而來的方法需要在方法定義前標(biāo)注override關(guān)鍵詞。通過這樣的操作可以確保你所要修改的這個(gè)方法確實(shí)是繼承而來的,而不會出現(xiàn)重寫錯(cuò)誤。錯(cuò)誤的重寫會造成一些不可預(yù)知的錯(cuò)誤,所以如果如果不標(biāo)記override關(guān)鍵詞的話,就會被在代碼編譯時(shí)報(bào)錯(cuò)。

override關(guān)鍵詞還能夠讓Swift編譯器檢查該類的父類是否有相符的方法,以確保你的重寫是可用的,正確的。

訪問父類方法,屬性和下標(biāo)

當(dāng)在重寫子類繼承自父類的方法,屬性或者下標(biāo)的時(shí)候,需要用到一部分父類已有的實(shí)現(xiàn)。比如你可以重定義已知的一個(gè)實(shí)現(xiàn)或者在繼承的變量中存儲一個(gè)修改的值。

適當(dāng)?shù)臅r(shí)候,可以通過使用super前綴來訪問父類的方法,屬性或者下標(biāo):

叫someMethod的重寫方法可以在實(shí)現(xiàn)的時(shí)候通過super.someMethod()調(diào)用父類的someMethod方法。

叫someProperty的重寫屬性可以在重寫實(shí)現(xiàn)getter或者setter的時(shí)候通過super.someProperty調(diào)用父類的someProperty。

叫someIndex的重寫下標(biāo)可以在實(shí)現(xiàn)下標(biāo)的時(shí)候通過super[someIndex]來訪問父類的下標(biāo)。

復(fù)寫方法

你可以在你的子類中實(shí)現(xiàn)定制的繼承于父類的實(shí)例方法或者類方法。

下面的例子演示的就是一個(gè)叫Car的Vehicle子類,重寫了繼承自Vehicle的description方法。

復(fù)制代碼代碼如下:

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è)新的Double類型的存儲屬性speed。這個(gè)屬性默認(rèn)值是0.0,意思是每小時(shí)0英里。Car還有一個(gè)自定義的構(gòu)造函數(shù),設(shè)置了最大乘客數(shù)為5,輪子數(shù)量是4.

Car重寫了繼承的description方法,并在方法名description前標(biāo)注了override關(guān)鍵詞。

在description中并沒有給出了一個(gè)全新的描述實(shí)現(xiàn),還是通過super.description使用了Vehicle提供的部分描述語句,然后加上了自己定義的一些屬性,如當(dāng)前速度。

如果你創(chuàng)建一個(gè)Car的實(shí)例,然后調(diào)用description方法,會發(fā)現(xiàn)描述語句變成了這樣:

復(fù)制代碼代碼如下:

let car = Car()

println("Car: \(car.description())")

// Car: 4 wheels; up to 5 passengers; traveling at 0.0 mph

復(fù)寫屬性

你還可以提供繼承自父類的實(shí)例屬性或者類屬性的個(gè)性化getter和setter方法,或者是添加屬性觀察者來實(shí)現(xiàn)重寫的屬性可以觀察到繼承屬性的變動。

重寫屬性的Getters和Setters

不管在源類中繼承的這個(gè)屬性是存儲屬性還是計(jì)算屬性,你都可以提供一個(gè)定制的getter或者setter方法來重寫這個(gè)繼承屬性。子類一般不會知道這個(gè)繼承的屬性本來是存儲屬性還是計(jì)算屬性,但是它知道這個(gè)屬性有特定的名字和類型。在重寫的時(shí)候需要指明屬性的類型和名字,好讓編譯器可以檢查你的重寫是否與父類的屬性相符。

你可以將一個(gè)只讀的屬性通過提那家getter和setter繼承為可讀寫的,但是反之不可。

注意:如果你為一個(gè)重寫屬性提供了setter方法,那么也需要提供getter方法。如果你不想在getter中修改繼承的屬性的值,可以在getter中使用super.someProperty即可,在下面SpeedLimitedCar例子中也是這樣。

下面的例子定義了一個(gè)新類SpeedLimitedCar,是Car的一個(gè)子類。這個(gè)類表示一個(gè)顯示在40碼一下的車輛。通過重寫繼承的speed屬性來實(shí)現(xiàn):

復(fù)制代碼代碼如下:

class SpeedLimitedCar: Car {

override var speed: Double? {

get {

return super.speed

}

set {

super.speed = min(newValue, 40.0)

}

}

}

每當(dāng)你要設(shè)置speed屬性的時(shí)候,setter都會檢查新值是否比40大,二者中較小的值會被設(shè)置給SpeedLimitedCar。

如果你嘗試為speed設(shè)置超過40的值,description的輸出依然還是40:

復(fù)制代碼代碼如下:

let limitedCar = SpeedLimitedCar()

limitedCar.speed = 60.0

println("SpeedLimitedCar: \(limitedCar.description())")

// SpeedLimitedCar: 4 wheels; up to 5 passengers; traveling at 40.0 mph

重寫屬性觀察者

你可以使用屬性重寫為繼承的屬性添加觀察者。這種做法可以讓你無論這個(gè)屬性之前是如何實(shí)現(xiàn)的,在繼承的這個(gè)屬性變化的時(shí)候都能得到提醒。更多相關(guān)的信息可以參考Property Observers這章。

注意:不能為繼承的常量存儲屬性或者是只讀計(jì)算屬性添加觀察者。這些屬性值是不能被修改的,因此不適合在重寫實(shí)現(xiàn)時(shí)添加willSet或者didSet方法。

注意:不能同時(shí)定義重寫setter和重寫屬性觀察者,如果想要觀察屬性值的變化,并且又為該屬性給出了定制的setter,那只需要在setter中直接獲得屬性值的變化就行了。

下面的代碼演示的是一個(gè)新類AutomaticCar,也是Car的一個(gè)子類。這個(gè)類表明一個(gè)擁有自動變速箱的汽車,可以根據(jù)現(xiàn)在的速度自動選擇檔位,并在description中輸出當(dāng)前檔位:

復(fù)制代碼代碼如下:

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)"

}

}

這樣就可以實(shí)現(xiàn),每次你設(shè)置speed的值的時(shí)候,didSet方法都會被調(diào)用,來看檔位是否需要變化。gear是由speed除以10加1計(jì)算得來,所以當(dāng)速度為35的時(shí)候,gear檔位為4:

復(fù)制代碼代碼如下:

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

4、禁止重寫

你可以通過標(biāo)記final關(guān)鍵詞來禁止重寫一個(gè)類的方法,屬性或者下標(biāo)。在定義的關(guān)鍵詞前面標(biāo)注@final屬性即可。

在子類中任何嘗試重寫父類的final方法,屬性或者下標(biāo)的行為都會在編譯時(shí)報(bào)錯(cuò)。同樣在擴(kuò)展中為類添加的方法,屬性或者下標(biāo)也可以被標(biāo)記為final。

還可以在類關(guān)鍵詞class前使用@final標(biāo)記一整個(gè)類為final(@final class)。任何子類嘗試?yán)^承這個(gè)父類時(shí)都會在編譯時(shí)報(bào)錯(cuò)。

繼承(inherit)? ?單向關(guān)系

?? 1、定義:某個(gè)類通過繼承語法而獲取另一個(gè)類的屬性和方法。

?? 2、最大好處:實(shí)現(xiàn)代碼復(fù)用(父類中的屬性和方法可以被子類直接使用),子類還可以拓展父類的方法和屬性

?? 3、缺點(diǎn):增加了程序“耦合性”(如:父類發(fā)生改變,子類代碼可能需要重新構(gòu)造,相關(guān)代碼也需要重新編譯)

?? 4、Swift中只有單繼承(通過“擴(kuò)展”和“協(xié)議”實(shí)現(xiàn)多繼承)

?? 5、!??!繼承是類與結(jié)構(gòu)和枚舉等類型最重要的區(qū)別之一

?? 6、?。?!Swift中不僅可以重寫方法還可以重寫屬性

構(gòu)造方法(構(gòu)造一個(gè)對象時(shí)被調(diào)用的方法)

?構(gòu)造方法最主要的作用就是:對對象進(jìn)行初始化(即給對象所占用的內(nèi)存進(jìn)行初始化)

[objc]?view plain?copy

/*

?*?類擴(kuò)展(extension關(guān)鍵字)

???給現(xiàn)有類添加一個(gè)方法,缺點(diǎn)是不能擴(kuò)展增加存儲屬性

?*/??

class?Person?{??

var?height:Double???

var?sex:Bool?=?true??

}??

extension?Person{??

//擴(kuò)展的構(gòu)造方法??

????convenience?init(height:Double){??

self.init()??

self.height?=?height??

????}??

//擴(kuò)展的計(jì)算屬性??

var?standardWeight:Double{??

let?e?=self.sex???22.0?:?20.0??

return?height!?*?height!?*?e??

????}??

//擴(kuò)展的普通方法??

????func?getResults()?->?String?{??

return?"計(jì)算體重"??

????}??

}??

var?p?=?Person(height:2.3)??

print(p.standardWeight)??

print(p.getResults())??


本文出自https://blog.csdn.net/minggeqingchun/article/details/54564888

http://www.jb51.net/article/59773.htm

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 123.繼承 一個(gè)類可以從另外一個(gè)類繼承方法,屬性和其他特征。當(dāng)一個(gè)類繼承另外一個(gè)類時(shí), 繼承類叫子類, 被繼承的...
    無灃閱讀 1,489評論 2 4
  • 本頁包含內(nèi)容: [TOC] 類里面的所有存儲型屬性——包括所有繼承自父類的屬性——都必須在構(gòu)造過程中設(shè)置初始值。 ...
    伍哥___閱讀 559評論 0 0
  • 本章將會介紹 存儲屬性的初始賦值自定義構(gòu)造過程默認(rèn)構(gòu)造器值類型的構(gòu)造器代理類的繼承和構(gòu)造過程可失敗構(gòu)造器必要構(gòu)造器...
    寒橋閱讀 832評論 0 0
  • 每個(gè)人都有一個(gè)死角, 自己走不出來,別人也闖不進(jìn)去。 我把最深沉的秘密放在那里。 你不懂我,我不怪你。 每個(gè)人都有...
    qtpifan閱讀 287評論 0 0
  • 太多的人,帶著偽裝的面具生活著,太累太累啦,我就是我,不需要為了別人的目光而活著,每天活出自己的模樣。
    2806淺嘗輒止閱讀 295評論 1 6

友情鏈接更多精彩內(nèi)容