/*
繼承與構造方法
(1)指定構造與便利構造方法解析
(2)派生類的構造方法
(3)構造器鏈和安全檢查深入解析
(4)派生類的構造方法默認繼承
(5)構造方法的重寫
(6)必須構造方法
(7)析構方法
*/
/*
(1)指定構造與便利構造方法解析(Designated Initializers and Convenience Initializers)
*/
class AB {
var a: Int
var b: Int
//指定構造方法, 不允許出現構造器代理,self.init(...)
init(a: Int, b: Int) {
self.a = a
self.b = b
print("Class AB init!")
}
//便利構造方法 -> 一定是通過調用其他的構造方法來實現初始化, self.init(...)
convenience init(a: Int) {
// self.a = a
// b = 0
self.init(a: a, b: 0)
}
convenience init() {
//調用指定構造方法
// self.init(a: 0, b: 0)
//調用便利構造方法
self.init(a: 0)
}
}
/*
(2)派生類的構造方法
*/
class CD: AB {
var c: Int
var d: Int
//構造方法默認是不會被繼承,基類的存儲屬性只能通過基類的構造方法來初始化
//派生類引入的存儲屬性要先被初始化,然後再調用父類的構造方法對父類的屬性進行初始化
//我們只能通過調用父類的指定構造方法來對父類的屬性進行初始化
init(c: Int, d: Int) {
self.c = c
self.d = d
super.init(a: 0, b: 0)
// super.init(a: 0)
}
}
/*
(3)構造器鏈-指定構造器和便利構造器之間的調用規則
總結:1.指定構造器必須調用其直接父類的指定構造器
2.便利構造器必須調用同類中定義的其他構造器.(既可以是
指定構造器,也可以是便利構造器)
3.便利構造器必須最終以調用一個指定構造器結束
指定構造器總是向上代理
便利構造器總是橫向代理
*/
class CD1: AB {
var c: Int
var d: Int
//指定構造器
init(c: Int, d: Int) {
self.c = c
self.d = d
super.init(a: 0, b: 0)
// super.init(a: 0)
}
//便利構造器, 只能通過調用本類中的構造器完成初始化,不允許出現super.init(...)
convenience init(a: Int, b: Int, c: Int, d: Int) {
self.init(c: c, d: d)
}
}
/*
(4)兩段式構造-構造過程可以劃分爲兩個階段
第一階段:確保所有的存儲屬性都初始化完畢
第二階段:對父類中的存儲屬性做進一步的處理.
作用:可以防止屬性在被初始化之前訪問,也可以防止屬性被另外
一個構造器意外的賦值.
*/
class A {
var a: Int
init(a: Int) {
self.a = a
}
}
class B: A {
var b: Int
init(a: Int, b: Int) {
//派生類引入的屬性進行初始化
print("類B第一階段初始化開始")
self.b = b
//父類的指定構造方法對父類的屬性進行初始化
//只能在第一階段之後才能夠訪問
// self.a = 1000
super.init(a: a)
print("類B第二階段初始化開始")
if (b > 100) {
self.a = 1000
}
}
}
class C: B {
var c: Int
init(a: Int, b: Int, c: Int) {
//派生類引入的屬性進行初始化
print("類C第一階段初始化開始")
self.c = c
//父類的指定構造方法對父類的屬性進行初始化
super.init(a: a, b: b)
print("類C第二階段初始化開始")
if (c > 1000) {
self.a = 1000
self.b = 1000
}
}
}
class D: C {
var d: Int
init(a: Int, b: Int, c: Int, d: Int) {
//派生類引入的屬性進行初始化
print("類D第一階段初始化開始")
self.d = d
//父類的指定構造方法對父類的屬性進行初始化
super.init(a: a, b: b, c: c)
print("類D第二階段初始化開始")
if (d > 1000) {
self.a = 1000
self.b = 1000
self.c = 1000
}
}
}
var d = D(a: 0, b: 0, c: 0, d: 0)
/*
(5)派生類構造方法定義時的編譯器安全性檢查
a 首先應該將派生類引入的存儲屬性初始化,然後再向上代理父類
的制定構造方法.
b 首先調用父類中的制定構造器實現父類中屬性的初始化之後,才
可以訪問父類中的屬性.
c 在編寫便利構造方法時,我們首先要調用同類中的其他構造方
法,然後纔可以訪問
d 在第一階段完成之前,不能調用任何實例方法,不能訪問任何
父類中定義的存儲屬性,也不能引用self
*/
class D1: C {
var d: Int
init(a: Int, b: Int, c: Int, d: Int) {
//派生類引入的屬性進行初始化
print("類D第一階段初始化開始")
self.d = d
//父類的指定構造方法對父類的屬性進行初始化
/*
(1)不可以訪問父類中的屬性
(2)不可以調用成員方法
*/
// self.test()
super.init(a: a, b: b, c: c)
print("類D第二階段初始化開始")
if (d > 1000) {
self.a = 1000
self.b = 1000
self.c = 1000
}
}
convenience init() {
//首先應該調用同類中的其他構造方法之後,纔可以訪問屬性
self.init(a: 0, b:0, c: 0, d:0)
a = 9
b = 3
c = 4
d = 90
}
func test() {
}
}
/*
(6)重寫指定構造方法
是指"子類中構造方法與父類中的構造方法的參數列表一模一樣"
*/
class Human {
let name: String
var age: Int
init(name: String, age: Int) {
self.name = name
self.age = age
}
}
class Woman: Human {
var haveBaby: Bool = false
//派生類中定義一個構造方法,它跟父類中的某個指定構造方法一樣
// override init(name: String, age: Int) {
// haveBaby = false
// super.init(name: name, age: age)
// }
init(name: String, age: Int, haveBaby: Bool) {
self.haveBaby = false
super.init(name: name, age: age)
}
convenience override init(name: String, age: Int) {
self.init(name: name, age: age, haveBaby: false)
}
}
/*
(7)重寫便利構造方法(其餘便利構造方法不存在重寫,只是爲了和上面的做對比,才起的這樣名)
*/
class Human1 {
let name: String
var age: Int
init(name: String, age: Int) {
self.name = name
self.age = age
}
convenience init() {
self.init(name:"", age: 0)
}
}
class Woman1: Human1 {
var haveBaby: Bool = false
//重寫成一個指定構造方法, 需要加上override關鍵字
override init(name: String, age: Int) {
haveBaby = false
super.init(name: name, age: age)
}
//重寫一個便利構造方法,也需要加上override關鍵字
// convenience override init(name: String, age: Int) {
// self.init(name: name, age: age, haveBaby: false)
// }
init(name: String, age: Int, haveBaby: Bool) {
self.haveBaby = false
super.init(name: name, age: age)
}
convenience init() {
self.init(name: "" , age: 0, haveBaby: false)
}
}
var w0 = Woman1()
/*
(8)構造器的自動繼承
a. 如果子類中沒有定義任何的構造方法,且子類中所有的存儲屬
性都有默認缺省值,會自動繼承父類中所有的構造方法(包括便利
構造方法);
b. 如果子類中只是重寫了父類中的某些(而不是全部)指定構造
方法,不管子類中的存儲屬性是否有缺省值,都不會繼承父類中的
其他構造方法;
c. 如果子類中重寫了父類中所有的指定構造方法,不管子類中的
存儲屬性是否有缺省值,都同時會繼承父類中所有的便利構造方
法;
*/
class XY {
var x: Int
var y: Int
init(x: Int, y: Int) {
self.x = x
self.y = y
}
init(x: Int){
self.x = x
self.y = 0
}
convenience init() {
self.init(x: 0, y: 0)
}
}
//對應上面的a結論,沒有任何構造方法
class XYZ: XY {
var z: Int = 10
//對應上面的a結論,沒有任何構造方法
// init(z: Int) {
// self.z = z
// super.init(x: 0, y: 0)
// }
}
//對應上面的b結論,只是重寫部分構造方法
class XYZ1: XY {
var z: Int = 10
// init(z: Int) {
// self.z = z
// super.init(x: 0, y: 0)
// }
override init(x: Int, y: Int) {
z = 10
super.init(x: x, y: y)
}
}
//對應上面的c結論,重寫父類所有構造方法
class XYZ2: XY {
var z: Int = 10
override init(x: Int, y: Int) {
z = 10
super.init(x: x, y: y)
}
override init(x: Int) {
z = 10
super.init(x: x, y: 0)
}
}
var t0 = XYZ()
var t1 = XYZ2(x: 0)
var t2 = XYZ1(x: 0, y: 0)
print(t0.z)
print(t1.z)
print(t2.z)
/*
(9)必須構造器,構造方法所屬的類的後續子類必須也得實現這個構造方法
*/
class Some {
var some: Int
//必須實現方法
required init() {
some = 0
}
}
class ChildOfSome: Some {
var sub: Int
init(sub: Int) {
self.sub = sub
super.init()
}
//子類也必須實現該方法
required init() {
sub = 0
super.init()
}
}
Swift 基礎學習(指定構造方法和便利構造方法)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.