• swift基础语法(28- 继承与构造方法, 指定构造与便利构造方法)


    指定构造与便利构造方法
    class Person {
        var name:String
        var age:Int
        指定构造方法都是以init开头的
        init(name:String, age:Int)
        {
            print("init")
            self.name = name
            self.age = age
        }
        如果是值类型没问题, 称之为构造器代理
        但如果是引用类型会报错, 需要在前面加上convenience关键字.
        被convenience关键字修饰的构造方法称之为便利构造器,
        通过调用其它构造方法来初始化.
        反而言之, 便利构造器中一定是调用其它构造方法初始化的
        一定要出现self.init
        convenience init()
        {
            print("convenience init")
            self.init(name:”qbs", age:30)
        }
         类可以拥有多个构造方法
        init(name:String)
        {
            print("init name")
            self.name = name
            self.age = 0
            不能在指定构造方法中调用便利构造方法
            也就是说指定构造方法中不能出现self.init
            self.init()
        }
       
        convenience init(age:Int)
        {
            print("convenience init age")
            可以在便利构造器中调用指定构造器
            self.init(name:”xmg", age:30)
            以在便利构造器中调用便利构造器
            self.init()
        }
         便利构造器不能和指定构造器同名
          convenience init(name:String)
          {
          }
    }
     
    var p = Person()
    输出结果:
    convenience init
    init
     
    var p1 = Person(age: 10)
    输出结果:
    convenience init age
    convenience init
    init
     
    var p2 = Person(name: "qbs")
    输出结果:
    init name
     
    var p3 = Person(name: "qbs", age: 20)
    输出结果:
    init
     
     
    派生类的构造方法
    class Man {
        var name:String
        指定构造方法
        init(name:String){
            print("Man init")
            self.name = name
        }
        便利构造方法
        convenience init(){
            print("Man convenience init")
            self.init(name:"convenience-qbs")
        }
    }

    class SuperMan: Man {
        var age: Int
        注意:
        1.默认情况下构造方法不会被继承
        2.基类的存储属性只能通过基类的构造方法初始化
        3.初始化存储属性时必须先初始化当前类再初始化父类
        4.不能通过便利构造方法初始化父类, 只能通过调用指定构造方法初始化父类
     
        指定构造器
        init(age:Int){
            self.age = age
            super.init(name: "qbs")
           不能通过便利构造方法初始化父类, 只能通过调用指定构造方法初始化父类
                     以下写法是错误的
            super.init()
        }
       
        func show(){
            print("age = (self.age) name=(self.name)")
        }
       
    }
    var p = Man()
    输出结果:
    Man convenience init
    Man init
     
    var p = SuperMan(age: 10)
    输出结果:
    SuperMan init
    Man init
     
    构造器间的调用规则
    >指定构造器必须调用其直接父类的"指定构造器"
    >便利构造器必须调用同类中的其它构造器(指定或便利)
    >便利构造器必须最终以调用一个指定构造器结束
     (无论调用的是指定还是便利, 最终肯定会调用一个指定构造器)
    *指定构造器总是向上代理(父类)
    *便利构造器总是横向代理(当前类)

    class Man {
        var name:String
        指定构造方法
        init(name:String){
            print("Man->init")
            self.name = name
        }
        便利构造方法
        convenience init(){
            print("Man->convenience init")
            self.init(name:"qbs")
        }
    }
    class SuperMan: Man {
        var age: Int
        指定构造器
        init(age:Int){
            print("SuperMan->init")
            self.age = age
            super.init(name: "qbs")
        }
        convenience init(){
             print("SuperMan->convenience init")
            self.init(age:30)
        }
        convenience init(name:String, age:Int){
             print("SuperMan->convenience init name age")
             调用子类构造器一定能够初始化所有属性
             便利构造器中只能通过self.init来初始化, 不能使用super.init
             因为调用父类构造器不一定能完全初始化所有属性(子类特有)
             super.init(name: “xmg")
            self.init()
        }
       
        func show(){
            print("name = (self.name) age = (self.age)")
        }
       
    }
     
    var p = SuperMan()
    p.show()
    输出结果:
    SuperMan->convenience init
    SuperMan->init
    Man->init
    name = qbs age = 30
     
    var p = SuperMan(age: 10)
    p.show()
    输出结果:
    SuperMan->init
    Man->init
    name = xmg age = 10
     
    var p = SuperMan(name: "qbs", age: 20)
    p.show()
    输出结果:
    SuperMan->convenience init name age
    SuperMan->convenience init
    SuperMan->init
    Man->init
    name = qbs age = 30
     
     
    两段式构造
    构造过程可以划分为两个阶段
    1.确保当前类和父类所有存储属性都被初始化
    2.做一些其它初始化操作
    好处: 1.可以防止属性在被初始化之前访问
         2.可以防止属性被另外一个构造器意外赋值
    注意:构造器的初始化永远是在所有类的第一阶段初始化完毕之后才会开始第二阶段

    编译器安全检查:
    1.必须先初始化子类特有属性, 再向上代理父类指定构造方法初始化父类属性
    2.只能在调用完父类指定构造器后才能访问父类属性
    3.在便利构造器中, 必须先调用同类其它构造方法后才能访问属性
    4.第一阶段完成前不能访问父类属性/也不能引用self和调用任何实例方法
     
    class Man {
        var name:String
        指定构造方法
        init(name:String){
            self.name = name
        }
        便利构造方法
        convenience init(){
            self.init(name:"qbs")
        }
    }

    class SuperMan: Man {
        var age: Int
        指定构造器
        init(age:Int){
            print("SuperMan第一阶段开始")
            对子类引入的属性初始化
            self.age = age
            代码会报错,因为调用self.name之前还没有对父类的name进行初始化
            即便在这个地方修改, 也会被后面的初始化语句覆盖
            if (age > 30){
              self.name = "zs"
            }
            对父类引入的属性进行初始化
            super.init(name: "qbs")
           
            print("SuperMan第二阶段开始")
            if age > 30 {
                self.name = "zs"
            }
        }
    }

    class MonkeyMan:SuperMan{
        var height:Double
        init(height:Double){
            print("MonkeyMan第一阶段开始")
            对子类引入的属性初始化
            self.height = 99.0
            对父类引入的属性进行初始化
            super.init(age: 30)
           
            print("MonkeyMan第二阶段开始")
            if height < 100.0{
                self.age = 50
            }
        }
    }
    var m = MonkeyMan(height: 20)
    输出结果:
    MonkeyMan第一阶段开始
    SuperMan
    第一阶段开始
    SuperMan
    第二阶段开始
    MonkeyMan第二阶段开始
     
    重写指定构造方法
    子类的构造方法和父类的一模一样
    class Man {
        var name:String
         指定构造方法
        init(name:String){
            self.name = name
        }
    }
    class SuperMan: Man {
        var age: Int
        init(){
            self.age = 30
            super.init(name: qbs")
        }
         如果子类中的构造器和父类一模一样
         必须加上override关键字, 表示重写父类方法
         在老版本的Swift语言中是不需要override关键字的, 新版本才推出的
         override init(name:String){
                self.age = 30
               super.init(name: name)
         }
       
        将父类的指定构造器重写成一个便利构造器
        也必须加上override关键字, 表示重写父类方法
        convenience override init(name:String){
            self.init(name:name)
            self.age = 30
        }
    }
    var p = SuperMan()
    输出结果:
    SuperMan init
    Man init
    便利构造方法不存在重写
    class Man {
        var name:String
        指定构造方法
        init(name:String){
            print("Man->init")
            self.name = name
        }
        convenience init(){
             print("Man->convenience init")
            self.init(name:"qbs")
        }
    }
    class SuperMan: Man {
        var age: Int
        init(age:Int){
            print("SuperMan->init")
            self.age = age
            super.init(name: "qbs")
        }
     Swift中便利构造方法不存在重写, 如果加上override关键字
     系统会去查找父类中有没有和便利构造方法一样的指定构造方法
     有就不报错, 没有就报错
     
     为什么便利构造器不能重写呢?
     因为便利构造器只能横向代理
     只能调用当前类的其它构造方法或指定方法,不可能调用super.所以不存在重写
     也就是说子类的便利构造方法不能直接访问父类的便利构造方法,所以不存在重写的概念
        convenience init(){
            print("SuperMan-> convenience init")
            self.init(age:30)
        }
    }
    var sm = SuperMan()
    输出结果:
    SuperMan-> convenience init
    SuperMan->init
    Man->init
     
    构造方法的自动继承
    1.如果子类中没有定义任何构造器, 且子类中所有的存储属性都有缺省值,
        会继承父类中所有的构造方法(包括便利构造器)
    2.如果子类中只是重写了父类中的某些指定构造器
      不管子类中的存储属性是否有缺省值, 都不会继承父类中的其它构造方法
    3.如果子类重写了父类中所有的指定构造器
      不管子类中的存储属性是否有缺省值, 都会同时继承父类中的所有便利方法
     
    class Person {
        var name:String
        var age:Int
        init(name:String, age:Int){
            print("Person init name age")
            self.name = name
            self.age = age
        }
        init(name:String){
             print("Person init name")
            self.name = name
            self.age = 0
        }
        convenience init(){
            print("Person convenience init")
            self.init(name:"qbs")
        }
    }
    class SuperMan: Person {
       
        var height:Double = 175.0
    }
    如果子类中没有定义任何构造器,
    且子类中所有的存储属性都有缺省值, 会继承父类中所有的构造方法(包括便利构造器).
    父类的存储属性是由父类的构造器初始化, 子类的存储属性是由缺省值初始化的.
    var p = SuperMan()
     
    如果子类中只是重写了父类中的某些指定构造器
    不管子类中的存储属性是否有缺省值, 都不会继承父类中的其它构造方法
    class SuperMan: Person {
        var height:Double = 175.0
        init(height:Double){
            self.height = height
            super.init(name: qbs", age: 30)
        }
    }
    var p = SuperMan()
     
    如果子类重写了父类中所有的指定构造器
    不管子类中的存储属性是否有缺省值, 都会同时继承父类中的所有便利方法
    class SuperMan: Person {
       
        var height:Double
       
        init(height:Double){
            self.height = height
            super.init(name: "qbs", age: 30)
        }
       
        override init(name:String, age:Int){
            self.height = 175.0
            super.init(name: name, age: age)
        }
        override init(name:String){
            self.height = 175.0
            super.init(name: name)
        }
       
    }
     
     
     
     
    必须构造器
    只要在构造方法的前面加上一个required关键字
    那么所有的子类(后续子类)只要定义了构造方法都必须实现该构造方法
    class Person {
        var name:String
        早期Swift版本中没有这个语法
        required init(name:String){
            print("Person init")
            self.name = name
        }
    }
    class SuperMan: Person {
        var age:Int = 30
        如果子类没有定义构造器, 可以不用重写
        init(){
            print("SuperMan init")
            self.age = 30
            super.init(name: "qbs")
        }
      1.如果子类自定义了构造器, 就必须重写"必须构造器"
        因为如果子类没有自定义任何构造器, 默认会继承父类构造器, 所以不用重写
      2.重写必须构造器不用加override关键字
        因为系统看到required关键字就会自动查看父类
        为什么重写了还需要加上required关键字, 因为所有后续子类都必须重写
        required init(name: String) {
            print("SuperMan init name")
            self.age = 30
            super.init(name:name)
        }
    }
    var sm = SuperMan(name: "qbs")
     
    输出结果:
    SuperMan init name
    Person init
     
      
  • 相关阅读:
    BZOJ 1412: [ZJOI2009]狼和羊的故事
    Bzoj 2443: [Usaco2011 Open]奇数度数
    Bzoj 1101: [POI2007]Zap
    BZOJ 2186: [Sdoi2008]沙拉公主的困惑
    BZOJ 4804: 欧拉心算 欧拉函数
    Luogu P3121 [USACO15FEB]审查(黄金)Censoring (Gold)
    Luogu P3000 [USACO10DEC]牛的健美操Cow Calisthenics
    BZOJ 2060: [Usaco2010 Nov]Visiting Cows 拜访奶牛
    BZOJ 3297: [USACO2011 Open]forgot
    BZOJ 2456: mode
  • 原文地址:https://www.cnblogs.com/jordanYang/p/5378532.html
Copyright © 2020-2023  润新知