文章目录
  1. 1. 1、Swift中继承的基本知识
  2. 2. 2、定义类的继承关系
  3. 3. 3、重写(Overriding)
    1. 3.1. 3.1、重写方法(Overriding Method)
      1. 3.1.1. 重写实例方法
      2. 3.1.2. 重写类方法
    2. 3.2. 3.2、重写属性(Overriding Property)
      1. 3.2.1. 重写实例属性
      2. 3.2.2. 重写属性观测器
  4. 4. 3.3、使用final来阻止重写

1、Swift中继承的基本知识

  • 只能类可以进行继承,结构体和枚举无法进行继承
  • Swift没有一个统一的基类,Objective-C中有一个基类NSObject
  • 如果一个类没有继承其他类,就自动成为一个基类
  • 子类会继承父类所有的属性和方法
  • 可以使用final来阻止继承
  • Swift不支持多继承
  • 可以使用重写(Overriding)来重新定义子类的一些行为。
  • 可以进行重写的有:方法,属性,属性观测器,下标脚本

2、定义类的继承关系

定义一个类继承另外一个类,语法跟很多语言一样,大家一看代码就懂。

1
2
3
4
class someClass : someSuperClass
{
//子类定义
}

下面举一个实际的例子,来逐步展开对继承的知识点的学习。
首先,我们定义一个Person的基类,来定义人类

1
2
3
4
5
6
7
8
9
class Person
{
var name: String = ""
var description: String
{
return "我叫(\name)"
}
}

然后,我们继续定义一个中国人,继承自人类

1
2
3
4
class Chinese : Person
{
var idCard : String = ""
}

Chinese类继承了Person类,也就继承了面的namedescription属性,可以使用Chinese的实例对这2个属性进行访问:

1
2
3
let chinese = Chinese()
chinese.name = "李雷" //设置父类的存储属性
chinese.description //="我叫李雷"

同样,Chinese类也可以被其他类继承,Chinese的子类除了拥有Chinese里面的属性和方法以外,还可以访问Chinese的父类Person的属性和方法:

1
2
3
4
5
6
7
8
9
class GuangdongPerson : Chinese
{
//定义广东人
}
let chinese = GuangdongPerson()
chinese.name = "李雷" //设置父类的存储属性
chinese.description //="我叫李雷"
chinese.idCard

3、重写(Overriding)

对于父类中的实例方法,类方法,实例属性,类属性和属性观测器,子类可以提供自己的实现,来覆盖父类的定义。这种行为,我们称之为重写(Overriding)。重写是用override关键字来标识。重写有以下知识点需要注意:

  • 通过override关键词修饰的方法和属性,必须在父类里面,有一个一模一样的定义名称(包括类型和返回值)。不然会报编译错误。
  • 重写内部定义可以使用super关键字访问父类对应的方法,属性和下标脚本。

3.1、重写方法(Overriding Method)

重写实例方法

重写实例方法比较简单,编写过代码的同学一看代码就懂:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Person
{
func officialHolidays()->String
{
return ""
}
}
class Chinese : Person
{
var idCard : String = ""
//重写父类函数
override func officialHolidays()->String
{
super.officialHolidays()
return "春节7天乐"
}
}
chinese.officialHolidays() //返回"春节7天乐"

重写类方法

在类中,类方法是使用关键字class修饰的方法,也可以使用static修饰,这时子类就不能重写。static相当于class+final的作用。注意这一点就行了,其他跟实例方法的逻辑是一样的。以下是一个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Person
{
//父类使用class修饰,如果使用static修饰,则子类不能重写该类方法
class func hasCultures() -> String
{
return "拥有智慧"
}
}
class Chinese : Person
{
override class func hasCultures() -> String
{
return "儒家文化"
}
}
Person.hasCultures() //返回"拥有智慧"
Chinese.hasCultures() //返回"儒家文化"

3.2、重写属性(Overriding Property)

重写属性有以下一些特点:

  • 子类可以对父类的实例属性和类属性进行重写
  • 子类可以将父类的存储属性和计算属性进行重写,子类重写必须为计算属性(提供gettersetter
  • 子类可以将只读属性重写为可读写的(提供gettersetter),但是不能将父类的读写属性重写为只读属性(只提供getter
  • 还可以重写属性观测器

重写实例属性

重写实例属性,其实是重写为gettersetter,重写为存储属性没有任何意义,因为你可以直接访问父类对应的存储属性。定义子类存储属性会产生编译错误:Cannot override with a stored property 'xxx'
同时我们也不能对一个父类let修饰的存储属性在子类中进行重写。因为常量在定义时就被赋值。

以下代码中,我们定义一个国家类,里面包含2个存储属性,一是人口数,二是人均GDP。然后定义一个计算属性,国家GDP,等于人口数*人均GDP。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class Country
{
var population : Int
var unitGDP : Double
init(population : Int, unitGDP: Double)
{
self.population = population
self.unitGDP = unitGDP
}
var totalGDP : Double
{
get
{
return Double(population) * unitGDP
}
set
{
self.unitGDP = newValue / Double(population)
}
}
}
let country = Country(population: 10, unitGDP: 10.0)
country.totalGDP //等于100

接下来我们定义中国类,假设在中国,统计人口有一定的误差率,所以我们要对totalGDP进行重写。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class China: Country {
var populationStatErrorRate : Double = 0
init()
{
super.init(population: 10, unitGDP: 10)
}
override var totalGDP : Double
{
get
{
return Double(population) * unitGDP
* (1 - populationStatErrorRate)
}
set
{
self.unitGDP = newValue /
(Double(population)*(1 - populationStatErrorRate))
}
}
}
let china = China()
china.populationStatErrorRate = 0.1
china.totalGDP //结果为90

在上面的例子中,我们可以看到如何在子类China中对totalGDP进行重写。

上例子中,以下情况也可以对totalGDP进行重写:

  • totalGDP可以定义成变量存储属性,即:
1
var totalGDP : Double = 0
  • totalGDP可以定义为只读计算属性
1
2
3
4
var totalGDP : Double
{
return Double(population) * unitGDP
}

此种情况,子类重写也可以只定义getter

  • totalGDP也可以是类型属性(class修饰的计算属性)

以下情况,重写将出现编译错误:

  • 当父类有gettersetter时,子类只提供重写的getter

重写属性观测器

重写属性观测器有以下一些限制:

  • 不能对常量存储属性和只读计算属性重新属性观测器,因为这2种情况,属性不能被设置
  • 不能同时重写setter,getter和属性观测器,因为getter,setter也可以观察到数值的变化

下面举一个例子来看看,如何重写属性观测器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class China: Country {
var populationStatErrorRate : Double = 0
init()
{
super.init(population: 10, unitGDP: 10)
}
override var totalGDP : Double
{
willSet
{
self.unitGDP = newValue / (Double(population)*(1 - populationStatErrorRate))
}
}
}
let china = China()
china.populationStatErrorRate = 0.1
china.totalGDP = 900
china.unitGDP //算出来是100

3.3、使用final来阻止重写

  • final关键字可以加在实例方法,类方法,实例属性,类属性和属性观测器前面,表示子类不能重写定义的内容
  • final也可以加在类定义前面,表示该类不能被重写,否则会报编译错误: Inheritance from a final class ‘xxx’`

  • static修饰方法和属性,同时代表class+final,也就是不能被重写

参考资料:

文章目录
  1. 1. 1、Swift中继承的基本知识
  2. 2. 2、定义类的继承关系
  3. 3. 3、重写(Overriding)
    1. 3.1. 3.1、重写方法(Overriding Method)
      1. 3.1.1. 重写实例方法
      2. 3.1.2. 重写类方法
    2. 3.2. 3.2、重写属性(Overriding Property)
      1. 3.2.1. 重写实例属性
      2. 3.2.2. 重写属性观测器
  4. 4. 3.3、使用final来阻止重写