通過定義構(gòu)造器(Initializers)來實(shí)現(xiàn)構(gòu)造過程,這些構(gòu)造器可以看做是用來創(chuàng)建特定類型新實(shí)例的特殊方法。與 Objective-C 中的構(gòu)造器不同,Swift 的構(gòu)造器無需返回值,它們的主要任務(wù)是保證新實(shí)例在第一次使用前完成正確的初始化。
存儲(chǔ)屬性的初始賦值
ps: 當(dāng)你為存儲(chǔ)型屬性設(shè)置默認(rèn)值或者在構(gòu)造器中為其賦值時(shí),它們的值是被直接設(shè)置的,不會(huì)觸發(fā)任何屬性觀察者(
property observers)。
默認(rèn)屬性值
ps: 如果一個(gè)屬性總是使用相同的初始值,那么為其設(shè)置一個(gè)默認(rèn)值比每次都在構(gòu)造器中賦值要好。兩種方法的效果是一樣的,只不過使用默認(rèn)值讓屬性的初始化和聲明結(jié)合得更緊密。使用默認(rèn)值能讓你的構(gòu)造器更簡潔、更清晰,且能通過默認(rèn)值自動(dòng)推導(dǎo)出屬性的類型;同時(shí),它也能讓你充分利用默認(rèn)構(gòu)造器、構(gòu)造器繼承等特性
參數(shù)的內(nèi)部名稱和外部名稱
然而,構(gòu)造器并不像函數(shù)和方法那樣在括號(hào)前有一個(gè)可辨別的名字。因此在調(diào)用構(gòu)造器時(shí),主要通過構(gòu)造器中的參數(shù)名和類型來確定應(yīng)該被調(diào)用的構(gòu)造器。正因?yàn)閰?shù)如此重要,如果你在定義構(gòu)造器時(shí)沒有提供參數(shù)的外部名字,Swift 會(huì)為每個(gè)構(gòu)造器的參數(shù)自動(dòng)生成一個(gè)跟內(nèi)部名字相同的外部名。
可選屬性類型
如果你定制的類型包含一個(gè)邏輯上允許取值為空的存儲(chǔ)型屬性——無論是因?yàn)樗鼰o法在初始化時(shí)賦值,還是因?yàn)樗谥竽硞€(gè)時(shí)間點(diǎn)可以賦值為空——你都需要將它定義為可選類型optional type。可選類型的屬性將自動(dòng)初始化為nil,表示這個(gè)屬性是有意在初始化時(shí)設(shè)置為空的。
默認(rèn)構(gòu)造器
如果結(jié)構(gòu)體或類的所有屬性都有默認(rèn)值,同時(shí)沒有自定義的構(gòu)造器,那么 Swift 會(huì)給這些結(jié)構(gòu)體或類提供一個(gè)默認(rèn)構(gòu)造器。這個(gè)默認(rèn)構(gòu)造器將簡單地創(chuàng)建一個(gè)所有屬性值都設(shè)置為默認(rèn)值的實(shí)例。
結(jié)構(gòu)體的逐一成員構(gòu)造器
除了上面提到的默認(rèn)構(gòu)造器,如果結(jié)構(gòu)體沒有提供自定義的構(gòu)造器,它們將自動(dòng)獲得一個(gè)逐一成員構(gòu)造器,即使結(jié)構(gòu)體的存儲(chǔ)型屬性沒有默認(rèn)值。
值類型的構(gòu)造器代理
如果你為某個(gè)值類型定義了一個(gè)自定義的構(gòu)造器,你將無法訪問到默認(rèn)構(gòu)造器(如果是結(jié)構(gòu)體,還將無法訪問逐一成員構(gòu)造器)。這個(gè)限制可以防止你為值類型定義了一個(gè)進(jìn)行額外必要設(shè)置的復(fù)雜構(gòu)造器之后,別人還是錯(cuò)誤地使用了一個(gè)自動(dòng)生成的構(gòu)造器。
ps: 假如你希望默認(rèn)構(gòu)造器、逐一成員構(gòu)造器以及你自己的自定義構(gòu)造器都能用來創(chuàng)建實(shí)例,可以將自定義的構(gòu)造器寫到擴(kuò)展(extension)中,而不是寫在值類型的原始定義中。
下面例子將定義一個(gè)結(jié)構(gòu)體Rect,用來代表幾何矩形。這個(gè)例子需要兩個(gè)輔助的結(jié)構(gòu)體Size和Point,它們各自為其所有的屬性提供了初始值0.0。你可以通過以下三種方式為Rect創(chuàng)建實(shí)例——使用被初始化為默認(rèn)值的origin和size屬性來初始化;提供指定的origin和size實(shí)例來初始化;提供指定的center和size來初始化。在下面Rect結(jié)構(gòu)體定義中,我們?yōu)檫@三種方式提供了三個(gè)自定義的構(gòu)造器:
struct Rect {
var origin = Point()
var size = Size()
init() {}
init(origin: Point, size: Size) {
self.origin = origin
self.size = size
}
init(center: Point, size: Size) {
let originX = center.x - (size.width / 2)
let originY = center.y - (size.height / 2)
self.init(origin: Point(x: originX, y: originY), size: size)
}
}
類的構(gòu)造器代理規(guī)則
為了簡化指定構(gòu)造器和便利構(gòu)造器之間的調(diào)用關(guān)系,Swift 采用以下三條規(guī)則來限制構(gòu)造器之間的代理調(diào)用:
規(guī)則 1
指定構(gòu)造器必須調(diào)用其直接父類的的指定構(gòu)造器。
規(guī)則 2
便利構(gòu)造器必須調(diào)用同一類中定義的其它構(gòu)造器。
規(guī)則 3
便利構(gòu)造器必須最終導(dǎo)致一個(gè)指定構(gòu)造器被調(diào)用。
一個(gè)更方便記憶的方法是:
- 指定構(gòu)造器必須總是向上代理
- 便利構(gòu)造器必須總是橫向代理

如圖所示,父類中包含一個(gè)指定構(gòu)造器和兩個(gè)便利構(gòu)造器。其中一個(gè)便利構(gòu)造器調(diào)用了另外一個(gè)便利構(gòu)造器,而后者又調(diào)用了唯一的指定構(gòu)造器。這滿足了上面提到的規(guī)則 2 和 3。這個(gè)父類沒有自己的父類,所以規(guī)則 1 沒有用到。
子類中包含兩個(gè)指定構(gòu)造器和一個(gè)便利構(gòu)造器。便利構(gòu)造器必須調(diào)用兩個(gè)指定構(gòu)造器中的任意一個(gè),因?yàn)樗荒苷{(diào)用同一個(gè)類里的其他構(gòu)造器。這滿足了上面提到的規(guī)則 2 和 3。而兩個(gè)指定構(gòu)造器必須調(diào)用父類中唯一的指定構(gòu)造器,這滿足了規(guī)則 1。
ps:這些規(guī)則不會(huì)影響類的實(shí)例如何創(chuàng)建。任何上圖中展示的構(gòu)造器都可以用來創(chuàng)建完全初始化的實(shí)例。這些規(guī)則只影響類定義如何實(shí)現(xiàn)。
下面圖例中展示了一種涉及四個(gè)類的更復(fù)雜的類層級(jí)結(jié)構(gòu)。它演示了指定構(gòu)造器是如何在類層級(jí)中充當(dāng)“管道”的作用,在類的構(gòu)造器鏈上簡化了類之間的相互關(guān)系。

兩段式構(gòu)造過程
Swift 中類的構(gòu)造過程包含兩個(gè)階段。第一個(gè)階段,每個(gè)存儲(chǔ)型屬性通過引入它們的類的構(gòu)造器來設(shè)置初始值。當(dāng)每一個(gè)存儲(chǔ)型屬性值被確定后,第二階段開始,它給每個(gè)類一次機(jī)會(huì)在新實(shí)例準(zhǔn)備使用之前進(jìn)一步定制它們的存儲(chǔ)型屬性。
兩段式構(gòu)造過程的使用讓構(gòu)造過程更安全,同時(shí)在整個(gè)類層級(jí)結(jié)構(gòu)中給予了每個(gè)類完全的靈活性。兩段式構(gòu)造過程可以防止屬性值在初始化之前被訪問,也可以防止屬性被另外一個(gè)構(gòu)造器意外地賦予不同的值。
ps: Swift 的兩段式構(gòu)造過程跟 Objective-C 中的構(gòu)造過程類似。最主要的區(qū)別在于階段 1,Objective-C 給每一個(gè)屬性賦值
0或空值(比如說0或nil)。Swift 的構(gòu)造流程則更加靈活,它允許你設(shè)置定制的初始值,并自如應(yīng)對(duì)某些屬性不能以0或nil作為合法默認(rèn)值的情況。
Swift 編譯器將執(zhí)行 4 種有效的安全檢查,以確保兩段式構(gòu)造過程能順利完成:
安全檢查 1
指定構(gòu)造器必須保證它所在類引入的所有屬性都必須先初始化完成,之后才能將其它構(gòu)造任務(wù)向上代理給父類中的構(gòu)造器。
如上所述,一個(gè)對(duì)象的內(nèi)存只有在其所有存儲(chǔ)型屬性確定之后才能完全初始化。為了滿足這一規(guī)則,指定構(gòu)造器必須保證它所在類引入的屬性在它往上代理之前先完成初始化。
安全檢查 2
指定構(gòu)造器必須先向上代理調(diào)用父類構(gòu)造器,然后再為繼承的屬性設(shè)置新值。如果沒這么做,指定構(gòu)造器賦予的新值將被父類中的構(gòu)造器所覆蓋。
安全檢查 3
便利構(gòu)造器必須先代理調(diào)用同一類中的其它構(gòu)造器,然后再為任意屬性賦新值。如果沒這么做,便利構(gòu)造器賦予的新值將被同一類中其它指定構(gòu)造器所覆蓋。
安全檢查 4
構(gòu)造器在第一階段構(gòu)造完成之前,不能調(diào)用任何實(shí)例方法,不能讀取任何實(shí)例屬性的值,不能引用self作為一個(gè)值。
類實(shí)例在第一階段結(jié)束以前并不是完全有效的。只有第一階段完成后,該實(shí)例才會(huì)成為有效實(shí)例,才能訪問屬性和調(diào)用方法。
以下是兩段式構(gòu)造過程中基于上述安全檢查的構(gòu)造流程展示:
階段 1
- 某個(gè)指定構(gòu)造器或便利構(gòu)造器被調(diào)用。
- 完成新實(shí)例內(nèi)存的分配,但此時(shí)內(nèi)存還沒有被初始化。
- 指定構(gòu)造器確保其所在類引入的所有存儲(chǔ)型屬性都已賦初值。存儲(chǔ)型屬性所屬的內(nèi)存完成初始化。
- 指定構(gòu)造器將調(diào)用父類的構(gòu)造器,完成父類屬性的初始化。
- 這個(gè)調(diào)用父類構(gòu)造器的過程沿著構(gòu)造器鏈一直往上執(zhí)行,直到到達(dá)構(gòu)造器鏈的最頂部。
- 當(dāng)?shù)竭_(dá)了構(gòu)造器鏈最頂部,且已確保所有實(shí)例包含的存儲(chǔ)型屬性都已經(jīng)賦值,這個(gè)實(shí)例的內(nèi)存被認(rèn)為已經(jīng)完全初始化。此時(shí)階段 1 完成。
階段 2
- 從頂部構(gòu)造器鏈一直往下,每個(gè)構(gòu)造器鏈中類的指定構(gòu)造器都有機(jī)會(huì)進(jìn)一步定制實(shí)例。構(gòu)造器此時(shí)可以訪問self、修改它的屬性并調(diào)用實(shí)例方法等等。
- 最終,任意構(gòu)造器鏈中的便利構(gòu)造器可以有機(jī)會(huì)定制實(shí)例和使用self。
構(gòu)造器的繼承和重寫
跟 Objective-C 中的子類不同,Swift 中的子類默認(rèn)情況下不會(huì)繼承父類的構(gòu)造器。Swift 的這種機(jī)制可以防止一個(gè)父類的簡單構(gòu)造器被一個(gè)更專業(yè)的子類繼承,并被錯(cuò)誤地用來創(chuàng)建子類的實(shí)例。
ps: 父類的構(gòu)造器僅會(huì)在安全和適當(dāng)?shù)那闆r下被繼承。
當(dāng)你在編寫一個(gè)和父類中指定構(gòu)造器相匹配的子類構(gòu)造器時(shí),你實(shí)際上是在重寫父類的這個(gè)指定構(gòu)造器。因此,你必須在定義子類構(gòu)造器時(shí)帶上override修飾符。即使你重寫的是系統(tǒng)自動(dòng)提供的默認(rèn)構(gòu)造器,也需要帶上override修飾符
ps: 當(dāng)你重寫一個(gè)父類的指定構(gòu)造器時(shí),你總是需要寫
override修飾符,即使你的子類將父類的指定構(gòu)造器重寫為了便利構(gòu)造器。
相反,如果你編寫了一個(gè)和父類便利構(gòu)造器相匹配的子類構(gòu)造器,由于子類不能直接調(diào)用父類的便利構(gòu)造器,因此,嚴(yán)格意義上來講,你的子類并未對(duì)一個(gè)父類構(gòu)造器提供重寫。最后的結(jié)果就是,你在子類中“重寫”一個(gè)父類便利構(gòu)造器時(shí),不需要加override前綴。
構(gòu)造器的自動(dòng)繼承
如上所述,子類在默認(rèn)情況下不會(huì)繼承父類的構(gòu)造器。但是如果滿足特定條件,父類構(gòu)造器是可以被自動(dòng)繼承的。在實(shí)踐中,這意味著對(duì)于許多常見場景你不必重寫父類的構(gòu)造器,并且可以在安全的情況下以最小的代價(jià)繼承父類的構(gòu)造器。
假設(shè)你為子類中引入的所有新屬性都提供了默認(rèn)值,以下 2 個(gè)規(guī)則適用:
規(guī)則 1
如果子類沒有定義任何指定構(gòu)造器,它將自動(dòng)繼承所有父類的指定構(gòu)造器。
規(guī)則 2
如果子類提供了所有父類指定構(gòu)造器的實(shí)現(xiàn)——無論是通過規(guī)則 1 繼承過來的,還是提供了自定義實(shí)現(xiàn)——它將自動(dòng)繼承所有父類的便利構(gòu)造器。(即使屬性沒有默認(rèn)值,只要實(shí)現(xiàn)了父類的所有指定構(gòu)造器,就會(huì)自動(dòng)繼承父類的所有便利構(gòu)造器)
即使你在子類中添加了更多的便利構(gòu)造器,這兩條規(guī)則仍然適用。
ps: 對(duì)于規(guī)則 2,子類可以將父類的指定構(gòu)造器實(shí)現(xiàn)為便利構(gòu)造器。
可失敗構(gòu)造器
如果一個(gè)類、結(jié)構(gòu)體或枚舉類型的對(duì)象,在構(gòu)造過程中有可能失敗,則為其定義一個(gè)可失敗構(gòu)造器。這里所指的“失敗”是指,如給構(gòu)造器傳入無效的參數(shù)值,或缺少某種所需的外部資源,又或是不滿足某種必要的條件等。
ps: 可失敗構(gòu)造器的參數(shù)名和參數(shù)類型,不能與其它非可失敗構(gòu)造器的參數(shù)名,及其參數(shù)類型相同。
嚴(yán)格來說,構(gòu)造器都不支持返回值。因?yàn)闃?gòu)造器本身的作用,只是為了確保對(duì)象能被正確構(gòu)造。因此你只是用return nil表明可失敗構(gòu)造器構(gòu)造失敗,而不要用關(guān)鍵字return來表明構(gòu)造成功。
帶原始值的枚舉類型的可失敗構(gòu)造器
帶原始值的枚舉類型會(huì)自帶一個(gè)可失敗構(gòu)造器init?(rawValue:),該可失敗構(gòu)造器有一個(gè)名為rawValue的參數(shù),其類型和枚舉類型的原始值類型一致,如果該參數(shù)的值能夠和某個(gè)枚舉成員的原始值匹配,則該構(gòu)造器會(huì)構(gòu)造相應(yīng)的枚舉成員,否則構(gòu)造失敗
類的可失敗構(gòu)造器
值類型(也就是結(jié)構(gòu)體或枚舉)的可失敗構(gòu)造器,可以在構(gòu)造過程中的任意時(shí)間點(diǎn)觸發(fā)構(gòu)造失敗。甚至在屬性被初始化前。
而對(duì)類而言,可失敗構(gòu)造器只能在類引入的所有存儲(chǔ)型屬性被初始化后,以及構(gòu)造器代理調(diào)用完成后,才能觸發(fā)構(gòu)造失敗。
class Product {
let name: String!
init?(name: String) {
self.name = name
if name.isEmpty { return nil }
}
}
構(gòu)造失敗的傳遞
類,結(jié)構(gòu)體,枚舉的可失敗構(gòu)造器可以橫向代理到類型中的其他可失敗構(gòu)造器。類似的,子類的可失敗構(gòu)造器也能向上代理到父類的可失敗構(gòu)造器。
class CartItem: Product {
let quantity: Int!
init?(name: String, quantity: Int) {
self.quantity = quantity
super.init(name: name)
if quantity < 1 { return nil }
}
}
重寫一個(gè)可失敗構(gòu)造器
如同其它的構(gòu)造器,你可以在子類中重寫父類的可失敗構(gòu)造器?;蛘吣阋部梢杂米宇惖姆强墒?gòu)造器重寫一個(gè)父類的可失敗構(gòu)造器。這使你可以定義一個(gè)不會(huì)構(gòu)造失敗的子類,即使父類的構(gòu)造器允許構(gòu)造失敗。
ps: 你可以用非可失敗構(gòu)造器重寫可失敗構(gòu)造器,但反過來卻不行。
當(dāng)你用子類的非可失敗構(gòu)造器重寫父類的可失敗構(gòu)造器時(shí),向上代理到父類的可失敗構(gòu)造器的唯一方式是對(duì)父類的可失敗構(gòu)造器的返回值進(jìn)行強(qiáng)制解包。
可失敗構(gòu)造器 init!
你可以在init?中代理到init!,反之亦然。你也可以用init?重寫init!,反之亦然。你還可以用init代理到init!,不過,一旦init!構(gòu)造失敗,則會(huì)觸發(fā)一個(gè)斷言。
必要構(gòu)造器
在類的構(gòu)造器前添加required修飾符表明所有該類的子類都必須實(shí)現(xiàn)該構(gòu)造器:
class SomeClass {
required init() {
// 構(gòu)造器的實(shí)現(xiàn)代碼
}
}
在子類重寫父類的必要構(gòu)造器時(shí),必須在子類的構(gòu)造器前也添加required修飾符,表明該構(gòu)造器要求也應(yīng)用于繼承鏈后面的子類。在重寫父類中必要的指定構(gòu)造器時(shí),不需要添加override修飾符
class SomeSubclass: SomeClass {
required init() {
// 構(gòu)造器的實(shí)現(xiàn)代碼
}
}
ps: 如果子類繼承的構(gòu)造器能滿足必要構(gòu)造器的要求,則無須在子類中顯式提供必要構(gòu)造器的實(shí)現(xiàn)。
通過閉包或函數(shù)設(shè)置屬性的默認(rèn)值
如果某個(gè)存儲(chǔ)型屬性的默認(rèn)值需要一些定制或設(shè)置,你可以使用閉包或全局函數(shù)為其提供定制的默認(rèn)值。每當(dāng)某個(gè)屬性所在類型的新實(shí)例被創(chuàng)建時(shí),對(duì)應(yīng)的閉包或函數(shù)會(huì)被調(diào)用,而它們的返回值會(huì)當(dāng)做默認(rèn)值賦值給這個(gè)屬性。
這種類型的閉包或函數(shù)通常會(huì)創(chuàng)建一個(gè)跟屬性類型相同的臨時(shí)變量,然后修改它的值以滿足預(yù)期的初始狀態(tài),最后返回這個(gè)臨時(shí)變量,作為屬性的默認(rèn)值。
class SomeClass {
let someProperty: SomeType = {
// 在這個(gè)閉包中給 someProperty 創(chuàng)建一個(gè)默認(rèn)值
// someValue 必須和 SomeType 類型相同
return someValue
}()
}
ps: 如果你使用閉包來初始化屬性,請(qǐng)記住在閉包執(zhí)行時(shí),實(shí)例的其它部分都還沒有初始化。這意味著你不能在閉包里訪問其它屬性,即使這些屬性有默認(rèn)值。同樣,你也不能使用隱式的
self屬性,或者調(diào)用任何實(shí)例方法。
例:
struct Checkerboard {
let boardColors: [Bool] = {
var temporaryBoard = [Bool]()
var isBlack = false
for i in 1...10 {
for j in 1...10 {
temporaryBoard.append(isBlack)
isBlack = !isBlack
}
isBlack = !isBlack
}
return temporaryBoard
}()
func squareIsBlackAtRow(row: Int, column: Int) -> Bool {
return boardColors[(row * 10) + column]
}
}
let board = Checkerboard()
print(board.squareIsBlackAtRow(0, column: 1))
// 打印 "true"
print(board.squareIsBlackAtRow(9, column: 9))
// 打印 "false"
要點(diǎn)總結(jié)
有兩點(diǎn)疑惑:
class Product {
let name: String!
init?(name: String) {
self.name = name
if name.isEmpty { return nil }
}
}
The
Productclass defined above is very similar to theAnimalstructure seen eariler.TheProductclass has a constantnameproperty that must not be allowed to take an empty string value.To enforce this requirement,theProductclass uses a failable initializer to ensure that the propety's value is nonempty before allowing initialization to succeed.
However,Productis a class,not a structure.This means that unlikeAnimal,any failable initializer for theProductclass must provide an initial value for thenameproperty before triggering an intialization failure.
In the example above,thenameproperty of theProductclass is defined as having an implicitly unwrapped optional string type(String!).Because it is of an optional type,this means that thenameproperty has a default value ofnilbefore it is assigned a specific value during initialization.This default value ofnilin turn means that all of the properties introduced by the Product class have a valid initial value.As a result,the failable intializer forProductcan trigger an initialization failure at the start of the intializer if it is passed an empty string,before assigning a specific value to thenameproperty within the initializer.
以上的代碼片段和描述都是從書上摘錄的。令我疑惑的是,根據(jù)描述來看,再init?的方法體里,self.name = name應(yīng)該放到 return nil下面去。意思是說optional在構(gòu)造過程的初期是默認(rèn)為nil,因此在構(gòu)造過程的開始時(shí)期就會(huì)觸發(fā)failure intializer。但實(shí)際情況是必須先給name一個(gè)初始值才能完成構(gòu)造過程,因?yàn)楦鶕?jù)安全檢查1,首先要對(duì)本類新引進(jìn)的存儲(chǔ)屬性初始化,然后安全檢查2,才會(huì)調(diào)用父類構(gòu)造器完成初始化,這樣看來,可失敗構(gòu)造器都是在完成所有構(gòu)造后才對(duì)。在xcode里也跑了一下,雖然上面的代碼是可以執(zhí)行的。但從運(yùn)行效果上來看,應(yīng)該是先完成了initialization,才進(jìn)行的可失敗判斷。
Conversely,if you write a subclass initializer that matches a superclass convenience initializer,that superclass convenience initializer can never be called directly by your subclass,as per the rules described above in Initializer Delegation For Class Types.Therefore, your subclass is not (strictly speaking)providing an override of the superclass initializer.As a result,you do not write the
overridemodifier when providing a matching implementation of a superclass convenience initializer.
對(duì)于這段描述,我個(gè)人的理解:
第一遍的理解:(后面有第二遍看到這里時(shí)的新理解)
子類的convenience initializer為什么在嚴(yán)格意義上沒有提供一個(gè)對(duì)父類convenience initializer的override?因?yàn)楦割惖腸onvenience initializer并不一定會(huì)被子類繼承(只有在某種情況下,也就是子類實(shí)現(xiàn)了所有父類的designated initializer才會(huì)觸發(fā)自動(dòng)繼承),所以當(dāng)子類沒有繼承該方法,而你要給該方法加一個(gè)override是不對(duì)的。在繼承了之后加override才是對(duì)的。這樣的話就是說有時(shí)候是override了,有時(shí)候不是override了。那么swift就干脆說這個(gè)地方不用寫override啦,就給大家省事了,你就不用去分析什么時(shí)候該寫override,什么時(shí)候不該寫override。編譯器也省得去校驗(yàn)啦。故此而有了這句話。
第二次看到這里的時(shí)候又有的新的理解:如前面一句所說,superclass的convenience initializer并不是直接的被subclass掉用。仔細(xì)推敲了一下這句話。普通的方法繼承可能是父類和子類里的那個(gè)方法實(shí)際上是同一個(gè)方法(即,地址空間是同一個(gè))而自動(dòng)繼承過來的convenience initializer并不和父類是同一個(gè)地址空間,而是單獨(dú)給子類開了一個(gè)地址空間,雖然函數(shù)體是一樣的。這個(gè)猜想等到實(shí)際理解了編譯器的override和方法繼承原理之后再來確定。強(qiáng)烈感覺第二個(gè)解釋是對(duì)的,第一個(gè)解釋略勉強(qiáng).