百日学 Swift(Day 10) – 类和继承

百日学 Swift(Day 10) – classes and inheritance(类和继承)

1. Creating your own classes(创建自定义类)test

类和结构体有 5 个区别。

区别 1:类永远不会带有成员初始化器。这意味着,如果类中有不带默认值的属性,则必须始终创建初始化程序对这些属性初始化。而结构体则不需要。

初始化器 initializer 在其他语言中或者称为 构造函数

2. Class inheritance(类的继承)test

区别 2:类可以继承,结构体不能。被继承的称为“父类”或“超类”,继承的类称为“子类”。子类拥有父类所有的属性和方法,还可以添加自己的属性和方法。

出于安全原因,初始化子类时总是要调用super.init()——以防万一父类在创建时会做一些重要的工作。**但要放在对子类的属性初始化之后。**父类属性不能直接先用 self 方式初始化,但在 super.init()之后可以使用 self 方式修改父类属性值。

class Person {			// 父类
    var name: String	// 父类属性
    var age: Int
    var description: String {"\(name) + \(age)"}	// 父类计算属性
    
    init(name: String, age: Int) {	// 父类的初始化器
        self.name = name
        self.age = age
    }
}

class Teacher: Person {		// 子类 继承 父类 Person
    var lesson: String		// 子类的属性
    var school: String = "雨燕中学"			// 带默认值的属性
    init(name: String, age: Int, lesson: String) {	// 子类的初始化
        // 初始化子类属性,
        // 一定要放在 super.init 之前,否则报错:
        // Property 'self.param' not initialized at implicitly generated super.init call
        self.lesson = lesson	
        // 调用父类初始化器,初始化父类属性
        // 如果只是使用 self.父类属性 进行初始化,一样会报错
        super.init(name: name, age: age)
    }
}

let t1 = Teacher(name: "张三", age: 41, lesson: "英语")
print("我是 \(t1.name), \(t1.age)岁. 我在 \(t1.school)\(t1.lesson) 。")
print("t1.decription : \(t1.description).")	// 计算属性也被赋值了

// 输出结果:空格是为了更好的显示属性的使用。
我是 张三, 41. 我在 雨燕中学 教 英语。
t1.decription : 张三 + 41.

记住:在初始化器或者声明属性的时候都可以为属性提供一个 默认值

3. Overriding methods(覆写方法)test

子类可以使用自己的实现替换父类的方法,这称为 覆写 overriding

class Person {                          // 父类
    var name: String                    // 父类属性
    var age: Int
    
    func ability() {                    // 父类方法
        print("我会吃喝拉撒睡")
    }
    
    init(name: String, age: Int) {      // 父类初始化
        self.name = name
        self.age = age
    }
}

class Teacher: Person {                 // 子类
    var lesson: String                  // 子类属性
    var school: String = "雨燕中学"
    
    override func ability() {           // 覆写父类方法
        print("我会教书.")
    }
    
    func ability(lesson: String) {      // 重载
        print("我会教\(lesson).")
    }
    
    init(name: String, age: Int, lesson: String) {      // 子类初始化
        self.lesson = lesson
        super.init(name: name, age: age)
    }
    
}

let t1 = Teacher(name: "张三", age: 31, lesson: "英语")
print("我是\(t1.name), 我\(t1.age)岁.")
t1.ability()
t1.ability(lesson: t1.lesson)
print("我在\(t1.school)\(t1.lesson).")

// 运行结果:
我是张三,31.
我会教书.
我会教英语.
我在雨燕中学教英语.

覆写重载的区别:

  • 覆写 overriding :同方法名,同参数名,同参数类型,同参数个数,同返回类型
  • 重载 overloading :同样的方法名、参数名、参数类型,参数个数和返回类型不同

4. Final classes(最终类)test

class 关键字前面加上 final 关键字,会将类声明为 final 类,任何其他类都不能继承该类。

5. Copying objects(复制对象)test

区别 3:类的对象复制,复制副本和原始副本指向同一个对象,改变其中一个会影响到另一个。而结构体则是分别指向两个对象。

class Person {
    var name: String = "张三"
}

var p1 = Person()
print("=== 复制前 ===")
print("p1.name : \(p1.name)")
print("=== 复制后 ===")
var p1Copy = p1                    // 复制 类 对象
p1Copy.name = "李四"
print("p1.name : \(p1.name)")
print("p1Copy.name : \(p1Copy.name)")
// 运行结果
=== 复制前 ===
p1.name : 张三
=== 复制后 ===
p1.name : 李四
p1Copy.name : 李四
struct Person {
    var name: String = "张三"
}

var p1 = Person()
print("=== 复制前 ===")
print("p1.name : \(p1.name)")
print("=== 复制后 ===")
var p1Copy = p1                    // 复制 结构体 对象
p1Copy.name = "李四"
print("p1.name : \(p1.name)")
print("p1Copy.name : \(p1Copy.name)")
// 运行结果
=== 复制前 ===
p1.name : 张三
=== 复制后 ===
p1.name : 张三
p1Copy.name : 李四

6. Deinitializers(析构器)test

区别 4 :类可以有反初始化器,有的语言可能称之为析构函数,这个函数在销毁类的实例的时候被调用。

class Person {
    var name = "张三"

    init() {							// 初始化器,构造函数
        print("创建一个对象:\(self)")
    }
    
    deinit {							// 反初始化器,析构函数
        print("\(self)  被销毁")
    }

    func printGreeting() {
        print("Hello, I'm \(name)")
    }
}

for _ in 1...3 {
    let person = Person()
    person.printGreeting()
}
// 运行结果
创建一个对象:__lldb_expr_43.Person
Hello, I'm 张三
__lldb_expr_43.Person  被销毁
创建一个对象:__lldb_expr_43.Person
Hello, I'm 张三
__lldb_expr_43.Person  被销毁
创建一个对象:__lldb_expr_43.Person
Hello, I'm 张三
__lldb_expr_43.Person  被销毁

7. Mutability(可变性)test

区别 5 :对于使用 let 声明的常量,如果是类,可以修改类中的变量属性;如果是结构体,则不能修改其中的变量属性(要想修改必须用var 声明)。

class Singer {
    var name = "Taylor Swift"
}

let taylor = Singer()		// taylor 为常量……
taylor.name = "Ed Sheeran"	// taylor 的变量属性 name 被修改了……
print(taylor.name)

8. Classes summary(类小结)test

  • 类和结构体相似,它们都可以使用属性和方法创建自定义类型。
  • 一个类可以从另一个类继承,并获得父类的所有属性和方法。谈论类层次结构是很常见的——一个类基于另一个,而另一个类本身又基于另一个。(一个类不能继承多个类,全是单线联系的地下党)
  • 可以使用final关键字标记一个类,这将阻止其他类从该类继承。
  • 通过方法重写,子类可以使用新的实现替换其父类中的方法。
  • 当两个变量指向同一类实例时,它们都指向同一块内存——改变一个会改变另一个。
  • 类可以具有一个反初始化器,该反初始化器是在销毁该类的实例时运行的代码。
  • 类并不像构造结构体那样强烈地强制执行常量——如果将类属性声明为变量,则无论是否将类实例声明为常量,都可以对其进行更改。
发布了51 篇原创文章 · 获赞 15 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/hh680821/article/details/105172711