Swift:继承专题

1. 多态性

import UIKit

class Avatar { // 角色
    var name: String
    var life = 100 {
        didSet { //  这里一定只能用didSet,在改变之后再次改变life的值,如果用willSet只能在内部改变,出去之后还是原样
            if life > 100 {
                life = 100
            }
        }
    }
    var isAlive: Bool {
        return life <= 0 ? false : true
    }
    
    init(name: String) {
        self.name = name
    }
    
    func beAttacked(attack: Int) {
        life -= attack
        if life < 0 {
            life = 0
        }
    }
}

class User: Avatar {
    var score = 0
    var level = 0
    
    func getScore(score: Int) {
        self.score += score
        if score > level * 100 { // 升级
            level += 1
        }
    }
}

final class Magician: User {
    var magic = 100
    func heal(user: User) { // 魔法师可以给User下面的所有子类治疗
        user.life += 200
    }
}

class Warrior: User {
    var weapon: String? // 可以不拿武器
}

class Monster: Avatar {
    func attack(user: User, amount: Int) {
        user.beAttacked(attack: amount)
    }
}

final class Zombie: Monster { // 僵尸
    var type: String = "Default"
}

let player1 = Magician(name: "aaa") // 也是User的对象,也是Avatar的对象
let player2 = Warrior(name: "bbb")
let zombie = Zombie(name: "ccc")
let monster = Monster(name: "ddd")

func printBasicInfo(avatar: Avatar) {
    print("名字是\(avatar.name),生命值是\(avatar.life),\(avatar.isAlive == true ? "活着" : "死了")")
}

printBasicInfo(avatar: player1)
printBasicInfo(avatar: player2)
printBasicInfo(avatar: zombie)
printBasicInfo(avatar: monster)

let avatar: [Avatar] = [player1, player2, zombie, monster] // 数组元素的类型是Avatar,可是存放的是Avatar的子类
for avatar in avatar {
    avatar.beAttacked(attack: 110)
}

printBasicInfo(avatar: player1)
printBasicInfo(avatar: player2)
printBasicInfo(avatar: zombie)
printBasicInfo(avatar: monster)

player1.heal(user: player1)
player1.heal(user: player2)
print(player1.life)
printBasicInfo(avatar: player1)
printBasicInfo(avatar: player2)


2. 两段式构造

在把所有属性全部初始化之前,不允许有逻辑涉及self自身

Ps,必须先初始化子类自己的属性,再调用父类的构造函数

import UIKit

class A {
    var x: Int
    var y: Int
    init(x: Int, y: Int) {
        self.x = x
        self.y = y
    }
}

class B: A {
    var z: Int
    init(x: Int, y: Int, z: Int) {
        // 构造初值
        self.z = z
        super.init(x: x, y: y)
        
        // 构造初值完毕,进行后续逻辑
        decX()
    }
    
    func decX()
    {
        x -= 1
    }
}

3. 构造函数和普通函数一样是可以有默认参数的,可以在括号里面就给参数赋初值

4. convenience关键字,用于修饰init构造函数,表示该构造函数里面还可以调用该类中其他的构造函数

5. convenience关键字修饰的函数中不允许出现super.init,必须要依靠一个指定的构造函数来实现

6.  构造函数的继承有两个规则

规则一:如果子类实现了父类所有指定构造函数,则自动继承父类的所有便利构造函数

代码如下

import UIKit

class A {
    var x: Int
    var y: Int
    init(x: Int, y: Int) {
        self.x = x
        self.y = y
    }
    convenience init(x: Int) {
        let y = 6
        self.init(x: x, y: y)
    }
    
    func printHello() {
        print("Hello!")
    }
}

class B: A { // B实现了父类的所有指定构造函数,因此B的实例可以调用A的所有指定构造函数和便利构造函数
    override init(x: Int, y: Int) {
        let xx = 2 * x
        let yy = 2 * y
        super.init(x: xx, y: yy)
    }
}

let b = B(x: 10)

解释,这里传入x为10,用的是父类的便利构造函数,因此先调用父类的便利构造函数,则此时x为10,y为6,由于在函数的最后还写了self.init(x: x, y: y),说明还要调本类中的构造函数,这里的类指的是父类,即A,但是在B中原有的构造函数被重载了,因此调用的其实是重载之后的构造函数,因此全部double啦,变成20和12!

下面来看一段代码

import UIKit

class A {
    var x: Int
    var y: Int
    init(x: Int, y: Int) {
        self.x = x
        self.y = y
    }
    convenience init(x: Int) {
        let y = 6
        self.init(x: x, y: y)
    }
    
    init() {
        self.x = 100
        self.y = 200
    }
    
    func printHello() {
        print("Hello!")
    }
}

class B: A { // B实现了父类的所有指定构造函数,因此B的实例可以调用A的所有指定构造函数和便利构造函数
    override init(x: Int, y: Int) {
        let xx = 2 * x
        let yy = 2 * y
        super.init(x: xx, y: yy)
    }

}

let b = B(x: 6)
b.x
b.y

我仅仅是在A中又加了一个指定的构造函数init(),传入为空,编译器就开始报错了。

报错的原因在于不满足规则一,B并没有重载A类所有的指定构造函数,A中指定的构造函数有两个,B却只实现了一个,因此,B也不会继承A中其他的便利函数。

如果在B中加入这样几行代码

override init() {
    print("Hello!")
    super.init()
}

就不报错了,因为这个时候B重写了A所有的指定构造函数,所以也自动继承了A的所有便利构造函数。

Ps:子类指定的构造函数一定要用super.init,不然肯定报错!

规则二:如果子类没有实现(这里的实现我认为是以重载方式去实现)父类的任何指定构造函数,则自动继承父类所有的指定构造函数

代码如下

import UIKit

class A {
    var x: Int
    var y: Int
    init(x: Int, y: Int) {
        self.x = x
        self.y = y
    }
    convenience init(x: Int) {
        let y = 6
        self.init(x: x, y: y)
    }
    
    init() {
        self.x = 100
        self.y = 200
    }
    
    func printHello() {
        print("Hello!")
    }
}

class B: A {
}

let b1 = B()
let b2 = B(x: 1)
let b3 = B(x: 1, y: 2)

这里B没有重载A的任何指定的构造函数,因此自动继承A的所有指定的构造函数,同时,根据规则一,如果子类实现了父类所有的指定构造函数,则自动继承父类的所有便利构造函数,因此你看b2那一行代码也是不报错的

7. 子类制定的构造函数一定要调用super.init,不然一定会报错

8. required 关键字,如果修饰父类的构造函数,表示该类的子类一定要实现(我理解为重载)该构造函数,并且父类和子类的都要用required关键字,子类不能写override。

9. 结构体因为没有继承,所以没有指定的构造函数和便利的构造函数一说。

猜你喜欢

转载自blog.csdn.net/shijie97/article/details/84064073