/*
   继承的概念和语法
(1)继承语法
(2)super关键字
(3)继承时的super关键字
(4)重写属性
(5)属性重写的限制
(6)重写属性观察器
(7)重写属性观察器的限制
(8)如何防止重写
*/

/*
(1) 继承语法
   继承是面向对象最显著的一个特性.继承是从已有的类中派生
出新的类,新的类能吸收已有类的数据属性和行为,并能扩展新的
能力.
    术语: 基类 (父类, 超类), 派生类 (子类, 继承类)
    swift继承的语法:
    class ChildClass: FatherClass {
    }
    继承优点: 代码重写
    继承缺点: 增加程序的耦合度, 父类的改变会影响子类
    swift没有多继承
*/
class Human {
    var name: String = ""
    var id: Int = 0
    func eat() {
        print("eat")
    }
    func drink() {
        print("drink")
    }
    func sleep() {
        print("sleep")
    }
}
class Woman: Human {
    func birth() {
        print("birth")
    }
}
let w = Woman()
let h = Human()
w.name = "傻女人"
w.eat()
w.sleep()
w.birth()
h.eat()
h.sleep()

/*
(2)super关键字
派生类中的方法实现中,可以通过super关键字来引用基类的属性和方法
*/
class Woman1: Human {
    func birth() {
        print("birth")
    }
    //派生类中使用基类的方法或属性
    func eatAndSleep() {
        super.eat() //查找是从父类开始
        super.sleep()
        birth()
    }
}

/*
(3)方法重写(override)
*/
class Woman2: Human {
    func birth() {
        print("birth")
    }
    //如果要重写方法,需要在最前面加上关键字override
    override func eat() {
        super.eat()
        print("\(name) eat!")
    }
    func eatAndSleep() {
        super.eat() //查找是从父类开始
        super.sleep()
        birth()
    }
}
let w2 = Woman2()
w2.name = "chun"
//通过子类的对象调用方法,优先使用本类中的重写方法
w2.eat()
w2.eatAndSleep()

/*
(4)重写属性
*/
class Father {
    var storeProperty: Int = 0 //存储属性
    var computerProperty: Int {//计算属性
        get {
            return 0
        }
        set {
            print("In father Class: set \(newValue)")
        }
    }
}
class Child: Father {
    //可以将一个父类的存储属性重写成计算属性, 不可以将存储属性又重写成存储属性
    override var storeProperty: Int {
        get {
            return 10
        }
        set {
            print("In Child class: set storeProperty with value \(newValue)")
        }
    }
    //可以将父类中的计算属性重写,重写的样式也是计算属性样式
    override var computerProperty: Int {
        get {
            return 2
        }
        set {
            print("In Child class: set computerProperty with value \(newValue)")
        }
    }
}
let ch = Child()
//通过子类的对象来调用重写后的属性或者方法,肯定会调用子类中的重写版本
ch.storeProperty = 100


/*
(5)属性重写的限制
1.属性重写的时候只有set方法没有get方法是否可以:不可以
2.只读的计算属性是否在重写的时候能够变成读写计算属性(权利变大): 可以
3.可读写的计算/存储属性是否可以重写为只读的计算属性 (权利变小): 不可以
*/

/*
(6)重写属观察器
1.只能给非lazy属性的变量存储属性设定属性观察器,不能给计
算属性设定属性观察器
(1)不可以给只读的存储/计算属性,在子类中设定属性观察器
*/
class Observer {
    var storeProperty: Int = 0 {
        willSet {

        }
        didSet {

        }
    }
    var computeProperty: Int {
        get {
            return 0
        }
        set {
            print("Do nothing!")
        }
    }
}
class ChildOfObserver: Observer {
    //可以重写父类中变量存储属性的属性观察器
    override var storeProperty: Int {
        willSet {
            print("will set")
        }
        didSet {
            print("did set")

        }
    }
    //可以重写父类中的计算属性观察器
    override var computeProperty: Int {
        willSet {
           print("compute willset")
        }
        didSet {
            print("compute didset")
        }
    }
}
let co = ChildOfObserver()
co.storeProperty = 10
co.computeProperty = 9

/*
(7)防止重写
final关键字修饰类的话,表示这个类不可以被继承
如果修饰属性或者方法,表示相应的属性或者方法不能被重写
*/
class Observer1 {
    final var storeProperty: Int = 0 {
        willSet {

        }
        didSet {

        }
    }
    var computeProperty: Int {
        get {
            return 0
        }
        set {
            print("Do nothing!")
        }
    }
}
class ChildOberver: Observer1 {
//    override var storeProperty: Int {
//        willSet {
//    
//        }
//        didSet {
//            
//        }
//
//    }
}