Swift Tour Learn (七) -- Swift 語(yǔ)法(下標(biāo)晦溪、繼承)

本章將會(huì)介紹

下標(biāo)語(yǔ)法
下標(biāo)用法
下標(biāo)選項(xiàng)
定義一個(gè)基類
子類生成
重寫
防止重寫

下標(biāo)

下標(biāo)可以定義在類、結(jié)構(gòu)體和枚舉中挣跋,是訪問(wèn)集合三圆,列表或序列中元素的快捷方式”芘兀可以使用下標(biāo)的索引舟肉,設(shè)置和獲取值,而不需要再調(diào)用對(duì)應(yīng)的存取方法牌借。舉例來(lái)說(shuō)度气,用下標(biāo)訪問(wèn)一個(gè)Array實(shí)例中的元素可以寫作someArray[index],訪問(wèn)Dictionary實(shí)例中的元素可以寫作someDictionary[key]膨报。

一個(gè)類型可以定義多個(gè)下標(biāo)磷籍,通過(guò)不同索引類型進(jìn)行重載。下標(biāo)不限于一維现柠,你可以定義具有多個(gè)入?yún)⒌南聵?biāo)滿足自定義類型的需求院领。

1.下標(biāo)語(yǔ)法

下標(biāo)允許你通過(guò)在實(shí)例名稱后面的方括號(hào)中傳入一個(gè)或者多個(gè)索引值來(lái)對(duì)實(shí)例進(jìn)行存取。語(yǔ)法類似于實(shí)例方法語(yǔ)法和計(jì)算型屬性語(yǔ)法的混合够吩。與定義實(shí)例方法類似比然,定義下標(biāo)使用subscript關(guān)鍵字,指定一個(gè)或多個(gè)輸入?yún)?shù)和返回類型周循;與實(shí)例方法不同的是强法,下標(biāo)可以設(shè)定為讀寫或只讀万俗。這種行為由 getter 和 setter 實(shí)現(xiàn),有點(diǎn)類似計(jì)算型屬性:

subscript(index: Int) -> Int {
    get {
      // 返回一個(gè)適當(dāng)?shù)?Int 類型的值
    }

    set(newValue) {
      // 執(zhí)行適當(dāng)?shù)馁x值操作
    }
}

newValue的類型和下標(biāo)的返回類型相同饮怯。如同計(jì)算型屬性闰歪,可以不指定 setter 的參數(shù)(newValue)。如果不指定參數(shù)蓖墅,setter 會(huì)提供一個(gè)名為newValue的默認(rèn)參數(shù)库倘。

如同只讀計(jì)算型屬性,可以省略只讀下標(biāo)的get關(guān)鍵字:

subscript(index: Int) -> Int {
    // 返回一個(gè)適當(dāng)?shù)?Int 類型的值
}

下面代碼演示了只讀下標(biāo)的實(shí)現(xiàn)论矾,這里定義了一個(gè)TimesTable結(jié)構(gòu)體教翩,用來(lái)表示傳入整數(shù)的乘法表:

struct TimesTable {
    let multiplier: Int
    subscript(index: Int) -> Int {
        return multiplier * index
    }
}
let threeTimesTable = TimesTable(multiplier: 3)
print("six times three is \(threeTimesTable[6])")
// 打印 "six times three is 18"

在上例中,創(chuàng)建了一個(gè)TimesTable實(shí)例贪壳,用來(lái)表示整數(shù)3的乘法表饱亿。數(shù)值3被傳遞給結(jié)構(gòu)體的構(gòu)造函數(shù),作為實(shí)例成員multiplier的值寥袭。

你可以通過(guò)下標(biāo)訪問(wèn)threeTimesTable實(shí)例路捧,例如上面演示的threeTimesTable[6]。這條語(yǔ)句查詢了3的乘法表中的第六個(gè)元素传黄,返回3的6倍即18。

注意
TimesTable例子基于一個(gè)固定的數(shù)學(xué)公式队寇,對(duì)threeTimesTable[someIndex]進(jìn)行賦值操作并不合適膘掰,因此下標(biāo)定義為只讀的。

2.下標(biāo)用法

下標(biāo)的確切含義取決于使用場(chǎng)景佳遣。下標(biāo)通常作為訪問(wèn)集合识埋,列表或序列中元素的快捷方式。你可以針對(duì)自己特定的類或結(jié)構(gòu)體的功能來(lái)自由地以最恰當(dāng)?shù)姆绞綄?shí)現(xiàn)下標(biāo)零渐。

例如窒舟,Swift 的Dictionary類型實(shí)現(xiàn)下標(biāo)用于對(duì)其實(shí)例中儲(chǔ)存的值進(jìn)行存取操作。為字典設(shè)值時(shí)诵盼,在下標(biāo)中使用和字典的鍵類型相同的鍵惠豺,并把一個(gè)和字典的值類型相同的值賦給這個(gè)下標(biāo):

var numberOfLegs = ["spider": 8, "ant": 6, "cat": 4]
numberOfLegs["bird"] = 2

上例定義一個(gè)名為numberOfLegs的變量,并用一個(gè)包含三對(duì)鍵值的字典字面量初始化它风宁。numberOfLegs字典的類型被推斷為[String: Int]洁墙。字典創(chuàng)建完成后,該例子通過(guò)下標(biāo)將String類型的鍵bird和Int類型的值2添加到字典中戒财。

注意
Swift 的Dictionary類型的下標(biāo)接受并返回可選類型的值热监。上例中的numberOfLegs字典通過(guò)下標(biāo)返回的是一個(gè)Int?或者說(shuō)“可選的int”。Dictionary類型之所以如此實(shí)現(xiàn)下標(biāo)饮寞,是因?yàn)椴皇敲總€(gè)鍵都有個(gè)對(duì)應(yīng)的值孝扛,同時(shí)這也提供了一種通過(guò)鍵刪除對(duì)應(yīng)值的方式列吼,只需將鍵對(duì)應(yīng)的值賦值為nil即可。

3.下標(biāo)選項(xiàng)

下標(biāo)可以接受任意數(shù)量的入?yún)⒖嗍迹⑶疫@些入?yún)⒖梢允侨我忸愋透曰丁O聵?biāo)的返回值也可以是任意類型。下標(biāo)可以使用變量參數(shù)和可變參數(shù)盈简,但不能使用輸入輸出參數(shù)凑耻,也不能給參數(shù)設(shè)置默認(rèn)值。

一個(gè)類或結(jié)構(gòu)體可以根據(jù)自身需要提供多個(gè)下標(biāo)實(shí)現(xiàn)柠贤,使用下標(biāo)時(shí)將通過(guò)入?yún)⒌臄?shù)量和類型進(jìn)行區(qū)分香浩,自動(dòng)匹配合適的下標(biāo),這就是下標(biāo)的重載臼勉。

雖然接受單一入?yún)⒌南聵?biāo)是最常見(jiàn)的邻吭,但也可以根據(jù)情況定義接受多個(gè)入?yún)⒌南聵?biāo)。例如下例定義了一個(gè)Matrix結(jié)構(gòu)體宴霸,用于表示一個(gè)Double類型的二維矩陣囱晴。Matrix結(jié)構(gòu)體的下標(biāo)接受兩個(gè)整型參數(shù):

struct Matrix {
    let rows: Int, columns: Int
    var grid: [Double]
    init(rows: Int, columns: Int) {
        self.rows = rows
        self.columns = columns
        grid = Array(repeatElement(0.0, count: rows * columns))
    }
    func indexIsValidForRow(row: Int, column: Int) -> Bool {
        return row >= 0 && row < rows && column >= 0 && column < columns
    }
    subscript(row: Int, column: Int) -> Double {
        get {
            assert(indexIsValidForRow(row, column: column), "Index out of range")
            return grid[(row * columns) + column]
        }
        set {
            assert(indexIsValidForRow(row, column: column), "Index out of range")
            grid[(row * columns) + column] = newValue
        }
    }
}

Matrix提供了一個(gè)接受兩個(gè)入?yún)⒌臉?gòu)造方法,入?yún)⒎謩e是rows和columns瓢谢,創(chuàng)建了一個(gè)足夠容納rows * columns個(gè)Double類型的值的數(shù)組畸写。通過(guò)傳入數(shù)組長(zhǎng)度和初始值0.0到數(shù)組的構(gòu)造器,將矩陣中每個(gè)位置的值初始化為0.0氓扛。

你可以通過(guò)傳入合適的row和column的數(shù)量來(lái)構(gòu)造一個(gè)新的Matrix實(shí)例:

var matrix = Matrix(rows: 2, columns: 2)

上例中創(chuàng)建了一個(gè)Matrix實(shí)例來(lái)表示兩行兩列的矩陣枯芬。該Matrix實(shí)例的grid數(shù)組按照從左上到右下的閱讀順序?qū)⒕仃嚤馄交鎯?chǔ):

將row和column的值傳入下標(biāo)來(lái)為矩陣設(shè)值,下標(biāo)的入?yún)⑹褂枚禾?hào)分隔:

matrix[0, 1] = 1.5
matrix[1, 0] = 3.2

上面兩條語(yǔ)句分別調(diào)用下標(biāo)的 setter 將矩陣右上角位置(即row為0采郎、column為1的位置)的值設(shè)置為1.5千所,將矩陣左下角位置(即row為1、column為0的位置)的值設(shè)置為3.2:


Matrix下標(biāo)的 getter 和 setter 中都含有斷言蒜埋,用來(lái)檢查下標(biāo)入?yún)ow和column的值是否有效淫痰。為了方便進(jìn)行斷言,Matrix包含了一個(gè)名為indexIsValidForRow(_:column:)的便利方法整份,用來(lái)檢查入?yún)ow和column的值是否在矩陣范圍內(nèi)待错,斷言在下標(biāo)越界時(shí)觸發(fā):

let someValue = matrix[2, 2]
// 斷言將會(huì)觸發(fā),因?yàn)?[2, 2] 已經(jīng)超過(guò)了 matrix 的范圍
4.下標(biāo)總結(jié)
下標(biāo)

// 下標(biāo)語(yǔ)法
struct TimesTable {
    let multiplier: Int
    subscript(index: Int) -> Int {
        return multiplier * index
    }
}
let threeTimesTable = TimesTable(multiplier: 3)
print("\(threeTimesTable[6])")


struct Matrix {
    let rows: Int, columns: Int
    var grid: [Double]

    init(rows: Int, columns: Int) {
        self.rows = rows
        self.columns = columns
        grid = Array(repeatElement(0.0, count: rows * columns))
    }

    func indexIsValidForRow(row: Int, column: Int) -> Bool {
        return row >= 0 && row < rows && column >= 0 && column < columns
    }

    subscript(row: Int, column: Int) -> Double {
        get {
            assert(indexIsValidForRow(row: row, column: column), "Index out of range")
            return grid[(row * columns) + column]
        }
        set {
            assert(indexIsValidForRow(row: row, column: column), "Index out of range")
            grid[(row * columns) + column] = newValue
        }
    }
}

var matrix = Matrix(rows: 2, columns: 2)
print(matrix.grid)
matrix[0, 1] = 1.5
matrix[0, 0] = 1.0
print(matrix.grid)

// matrix[2, 2] = 19

繼承

一個(gè)類可以繼承另一個(gè)類的方法皂林,屬性和其它特性朗鸠。當(dāng)一個(gè)類繼承其它類時(shí),繼承類叫子類础倍,被繼承類叫超類(或父類)烛占。在 Swift 中,繼承是區(qū)分「類」與其它類型的一個(gè)基本特征。

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

可以為類中繼承來(lái)的屬性添加屬性觀察器称杨,這樣一來(lái),當(dāng)屬性值改變時(shí)筷转,類就會(huì)被通知到姑原。可以為任何屬性添加屬性觀察器呜舒,無(wú)論它原本被定義為存儲(chǔ)型屬性還是計(jì)算型屬性锭汛。

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

不繼承于其它類的類,稱之為基類袭蝗。

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

下面的例子定義了一個(gè)叫Vehicle的基類朵逝。這個(gè)基類聲明了一個(gè)名為currentSpeed,默認(rèn)值是0.0的存儲(chǔ)屬性(屬性類型推斷為Double)左电。currentSpeed屬性的值被一個(gè)String類型的只讀計(jì)算型屬性description使用廉侧,用來(lái)創(chuàng)建車輛的描述。

Vehicle基類也定義了一個(gè)名為makeNoise的方法篓足。這個(gè)方法實(shí)際上不為Vehicle實(shí)例做任何事,但之后將會(huì)被Vehicle的子類定制:

class Vehicle {
    var currentSpeed = 0.0
    var description: String {
        return "traveling at \(currentSpeed) miles per hour"
    }
    func makeNoise() {
        // 什么也不做-因?yàn)檐囕v不一定會(huì)有噪音
    }
}

您可以用初始化語(yǔ)法創(chuàng)建一個(gè)Vehicle的新實(shí)例闰蚕,即類名后面跟一個(gè)空括號(hào):

let someVehicle = Vehicle()

現(xiàn)在已經(jīng)創(chuàng)建了一個(gè)Vehicle的新實(shí)例栈拖,你可以訪問(wèn)它的description屬性來(lái)打印車輛的當(dāng)前速度:

print("Vehicle: \(someVehicle.description)")
// 打印 "Vehicle: traveling at 0.0 miles per hour"

Vehicle類定義了一個(gè)通用特性的車輛類,實(shí)際上沒(méi)什么用處没陡。為了讓它變得更加有用涩哟,需要完善它從而能夠描述一個(gè)更加具體類型的車輛。

2.子類生成

子類生成指的是在一個(gè)已有類的基礎(chǔ)上創(chuàng)建一個(gè)新的類盼玄。子類繼承超類的特性贴彼,并且可以進(jìn)一步完善。你還可以為子類添加新的特性埃儿。

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

class SomeClass: SomeSuperclass {
    // 這里是子類的定義
}

下一個(gè)例子,定義一個(gè)叫Bicycle的子類精钮,繼承成父類Vehicle:

class Bicycle: Vehicle {
    var hasBasket = false
}

新的Bicycle類自動(dòng)獲得Vehicle類的所有特性威鹿,比如currentSpeed和description屬性,還有它的makeNoise()方法轨香。

除了它所繼承的特性忽你,Bicycle類還定義了一個(gè)默認(rèn)值為false的存儲(chǔ)型屬性hasBasket(屬性推斷為Bool)。

默認(rèn)情況下臂容,你創(chuàng)建任何新的Bicycle實(shí)例將不會(huì)有一個(gè)籃子(即hasBasket屬性默認(rèn)為false)科雳,創(chuàng)建該實(shí)例之后,你可以為特定的Bicycle實(shí)例設(shè)置hasBasket屬性為ture:

let bicycle = Bicycle()
bicycle.hasBasket = true

你還可以修改Bicycle實(shí)例所繼承的currentSpeed屬性脓杉,和查詢實(shí)例所繼承的description屬性:

bicycle.currentSpeed = 15.0
print("Bicycle: \(bicycle.description)")
// 打印 "Bicycle: traveling at 15.0 miles per hour"

子類還可以繼續(xù)被其它類繼承糟秘,下面的示例為Bicycle創(chuàng)建了一個(gè)名為Tandem(雙人自行車)的子類:

class Tandem: Bicycle {
    var currentNumberOfPassengers = 0
}

Tandem從Bicycle繼承了所有的屬性與方法,這又使它同時(shí)繼承了Vehicle的所有屬性與方法丽已。Tandem也增加了一個(gè)新的叫做currentNumberOfPassengers的存儲(chǔ)型屬性蚌堵,默認(rèn)值為0。

如果你創(chuàng)建了一個(gè)Tandem的實(shí)例沛婴,你可以使用它所有的新屬性和繼承的屬性吼畏,還能查詢從Vehicle繼承來(lái)的只讀屬性description:

let tandem = Tandem()
tandem.hasBasket = true
tandem.currentNumberOfPassengers = 2
tandem.currentSpeed = 22.0
print("Tandem: \(tandem.description)")
// 打印:"Tandem: traveling at 22.0 miles per hour"
3.重寫

子類可以為繼承來(lái)的實(shí)例方法嘁灯,類方法泻蚊,實(shí)例屬性,或下標(biāo)提供自己定制的實(shí)現(xiàn)丑婿。我們把這種行為叫重寫性雄。

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

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

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

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

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

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

重寫方法

在子類中并村,你可以重寫繼承來(lái)的實(shí)例方法或類方法,提供一個(gè)定制或替代的方法實(shí)現(xiàn)滓技。下面的例子定義了Vehicle的一個(gè)新的子類哩牍,叫Train,它重寫了從Vehicle類繼承來(lái)的makeNoise()方法:

class Train: Vehicle {
    override func makeNoise() {
        print("Choo Choo")
    }
}

如果你創(chuàng)建一個(gè)Train的新實(shí)例令漂,并調(diào)用了它的makeNoise()方法膝昆,你就會(huì)發(fā)現(xiàn)Train版本的方法被調(diào)用:

let train = Train()
train.makeNoise()
// 打印 "Choo Choo"

重寫屬性

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

  • 重寫屬性的 Getters 和 Setters

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

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

注意
如果你在重寫屬性中提供了 setter辟犀,那么你也一定要提供 getter摊阀。如果你不想在重寫版本中的 getter 里修改繼承來(lái)的屬性值,你可以直接通過(guò)super.someProperty來(lái)返回繼承來(lái)的值踪蹬,其中someProperty是你要重寫的屬性的名字。

以下的例子定義了一個(gè)新類臣咖,叫Car跃捣,它是Vehicle的子類。這個(gè)類引入了一個(gè)新的存儲(chǔ)型屬性叫做gear夺蛇,默認(rèn)值為整數(shù)1疚漆。Car類重寫了繼承自Vehicle的description屬性,提供包含當(dāng)前檔位的自定義描述:

class Car: Vehicle {
    var gear = 1
    override var description: String {
        return super.description + " in gear \(gear)"
    }
}

重寫的description屬性首先要調(diào)用super.description返回Vehicle類的description屬性。之后娶聘,Car類版本的description在末尾增加了一些額外的文本來(lái)提供關(guān)于當(dāng)前檔位的信息闻镶。

如果你創(chuàng)建了Car的實(shí)例并且設(shè)置了它的gear和currentSpeed屬性,你可以看到它的description返回了Car中的自定義描述:

let car = Car()
car.currentSpeed = 25.0
car.gear = 3
print("Car: \(car.description)")
// 打印 "Car: traveling at 25.0 miles per hour in gear 3"
  • 重寫屬性觀察器

你可以通過(guò)重寫屬性為一個(gè)繼承來(lái)的屬性添加屬性觀察器丸升。這樣一來(lái)铆农,當(dāng)繼承來(lái)的屬性值發(fā)生改變時(shí),你就會(huì)被通知到狡耻,無(wú)論那個(gè)屬性原本是如何實(shí)現(xiàn)的墩剖。

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

下面的例子定義了一個(gè)新類叫AutomaticCar,它是Car的子類背捌。AutomaticCar表示自動(dòng)擋汽車毙籽,它可以根據(jù)當(dāng)前的速度自動(dòng)選擇合適的擋位:

class AutomaticCar: Car {
    override var currentSpeed: Double {
        didSet {
            gear = Int(currentSpeed / 10.0) + 1
        }
    }
}

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

let automatic = AutomaticCar()
automatic.currentSpeed = 35.0
print("AutomaticCar: \(automatic.description)")
// 打印 "AutomaticCar: traveling at 35.0 miles per hour in gear 4"
4.防止重寫

你可以通過(guò)把方法,屬性或下標(biāo)標(biāo)記為final來(lái)防止它們被重寫吞琐,只需要在聲明關(guān)鍵字前加上final修飾符即可(例如:final var捆探,final func,final class func站粟,以及final subscript)黍图。

如果你重寫了帶有final標(biāo)記的方法,屬性或下標(biāo)奴烙,在編譯時(shí)會(huì)報(bào)錯(cuò)助被。在類擴(kuò)展中的方法剖张,屬性或下標(biāo)也可以在擴(kuò)展的定義里標(biāo)記為 final 的。

你可以通過(guò)在關(guān)鍵字class前添加final修飾符(final class)來(lái)將整個(gè)類標(biāo)記為 final 的揩环。這樣的類是不可被繼承的搔弄,試圖繼承這樣的類會(huì)導(dǎo)致編譯報(bào)錯(cuò)。

5.繼承總結(jié)
繼承

// 定義一個(gè)基類
class Vechicle {
    var currentSpeed = 0.0
    var description: String {
        return "traveling at \(currentSpeed) miles per hour"
    }

    func makeNoise() {
        // 什么也不做丰滑,有的車輛不一定會(huì)有噪音
    }
}

// 初始化語(yǔ)法創(chuàng)建實(shí)例
let someVechicle = Vechicle()
print(someVechicle.description)

// 子類生成
class Bicycle: Vechicle {
    var hasBasket = false
}
let bicycle = Bicycle()
bicycle.hasBasket = true
bicycle.currentSpeed = 15.0
print(bicycle.description)

class Tandem: Bicycle {
    var currentNumberOfPassengers = 0
}
let tandem = Tandem()
tandem.hasBasket = true
tandem.currentNumberOfPassengers = 2
tandem.currentSpeed = 22.0
print(tandem.description)

// 重寫方法
class Train: Vechicle {
    override func makeNoise() {
        print("Choo Choo")
    }
}
let train = Train()
train.makeNoise()

// 重寫屬性
class Car: Vechicle {
    var gear = 1
    override var description: String {
        return super.description + " in gear \(gear)"
    }
}
let car = Car()
car.currentSpeed = 25.0
car.gear = 3
print(car.description)

// 重寫屬性觀察器
class AutomaticCar: Car {
    override var currentSpeed: Double {
        didSet {
            gear = Int((currentSpeed / 10.0) + 1)
        }
    }
}
let automatic = AutomaticCar()
automatic.currentSpeed = 35.0
print(automatic.gear)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末顾犹,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子吨枉,更是在濱河造成了極大的恐慌蹦渣,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,378評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件貌亭,死亡現(xiàn)場(chǎng)離奇詭異柬唯,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)圃庭,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門锄奢,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人剧腻,你說(shuō)我怎么就攤上這事拘央。” “怎么了书在?”我有些...
    開封第一講書人閱讀 152,702評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵灰伟,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我儒旬,道長(zhǎng)栏账,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,259評(píng)論 1 279
  • 正文 為了忘掉前任栈源,我火速辦了婚禮挡爵,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘甚垦。我一直安慰自己茶鹃,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,263評(píng)論 5 371
  • 文/花漫 我一把揭開白布艰亮。 她就那樣靜靜地躺著闭翩,像睡著了一般。 火紅的嫁衣襯著肌膚如雪迄埃。 梳的紋絲不亂的頭發(fā)上男杈,一...
    開封第一講書人閱讀 49,036評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音调俘,去河邊找鬼伶棒。 笑死,一個(gè)胖子當(dāng)著我的面吹牛彩库,可吹牛的內(nèi)容都是我干的肤无。 我是一名探鬼主播,決...
    沈念sama閱讀 38,349評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼骇钦,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼宛渐!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起眯搭,我...
    開封第一講書人閱讀 36,979評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤窥翩,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后鳞仙,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體寇蚊,經(jīng)...
    沈念sama閱讀 43,469評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,938評(píng)論 2 323
  • 正文 我和宋清朗相戀三年棍好,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了仗岸。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,059評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡借笙,死狀恐怖扒怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情业稼,我是刑警寧澤盗痒,帶...
    沈念sama閱讀 33,703評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站低散,受9級(jí)特大地震影響俯邓,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜谦纱,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,257評(píng)論 3 307
  • 文/蒙蒙 一看成、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧跨嘉,春花似錦川慌、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至亮瓷,卻和暖如春琴拧,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背嘱支。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工蚓胸, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留挣饥,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,501評(píng)論 2 354
  • 正文 我出身青樓沛膳,卻偏偏與公主長(zhǎng)得像扔枫,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子锹安,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,792評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容