在 Swift 中,继承是区分「类」与其它类型的一个基本特征。swift不支持多重继承。类可以调用和访问超类的方法,属性和subscripts下标,并且可以重写(override)这些方法,属性和附属脚本来优化或修改它们的行为。Swift 会检查你的重写定义在超类中是否有匹配的定义,以此确保你的重写行为是正确的。

 可以为类中继承来的属性添加属性观察器(property observer),这样一来,当属性值改变时,类就会被通知到。可以为任何属性添加属性观察器,无论它原本被定义为存储型属性(stored property)还是计算型属性(computed property)。

  

  基类的定义

  不继承于其它类的类,称之为基类(base calss)

注意:Swift 中的类并不是从一个通用的基类继承而来。如果你不为你定义的类指定一个超类的话,这个类就自动成为基类。
下面的例子定义了一个叫Vehicle的基类。这个基类声明了两个对所有车辆都通用的属性(numberOfWheels和maxPassengers)。这些属性在description方法中使用,这个方法返回一个String类型的,对车辆特征的描述:
class Vehicle {
var numberOfWheels: Int
var maxPassengers: Int
func description() -> String {
return "\(numberOfWheels) wheels; up to \(maxPassengers) passengers"
}
init() {
numberOfWheels =
maxPassengers =
}
}
 
  子类化
 
   子类化是子类继承超类的特性,并且可以优化或改变它。你还可以为子类添加新的特性。
为了指明某个类的超类,将超类名写在子类名的后面,用冒号分隔:
class SomeClass: SomeSuperclass {
// 类的定义
}
下一个例子,定义一个更具体的车辆类叫Bicycle。这个新类是在 Vehicle类的基础上创建起来。因此你需要将Vehicle类放在 Bicycle类后面,用冒号分隔。
class Bicycle: Vehicle {
init() {
super.init()
numberOfWheels =
}
}
Bicycle是Vehicle的子类,Vehicle是Bicycle的超类。新的Bicycle类自动获得Vehicle类的特性,比如 maxPassengers和numberOfWheels属性。你可以在子类中定制这些特性,或添加新的特性来更好地描述Bicycle类。
 
Bicycle类定义了一个构造器来设置它定制的特性(自行车只有2个轮子)。Bicycle的构造器调用了它父类Vehicle的构造器 super.init(),以此确保在Bicycle类试图修改那些继承来的属性前Vehicle类已经初始化过它们了。
 
注意:不像 Objective-C,在 Swift 中,初始化器默认是不继承的。
 
Vehicle类中maxPassengers的默认值对自行车来说已经是正确的,因此在Bicycle的构造器中并没有改变它。而numberOfWheels原来的值对自行车来说是不正确的,因此在初始化器中将它更改为 2。
 
Bicycle不仅可以继承Vehicle的属性,还可以继承它的方法。如果你创建了一个Bicycle类的实例,你就可以调用它继承来的description方法,并且可以看到,它输出的属性值已经发生了变化:
 
let bicycle = Bicycle()
println("Bicycle: \(bicycle.description())")
// Bicycle: 2 wheels; up to 1 passengers

子类还可以继续被其它类继承:

class Tandem: Bicycle {
init() {
super.init()
maxPassengers =
}
}

意:子类只允许修改从超类继承来的变量属性,而不能修改继承来的常量属性。

  重写(Overriding)

  子类可以为继承来的实例方法(instance method),类方法(class method),实例属性(instance property),或subscript提供自己的实现(implementation)。我们把这种行为叫重写(overriding)。使用override关键字来实现,意外的重写行为可能会导致不可预知的错误,任何缺少override关键字的重写都会在编译时检查为错误。override关键字会提醒 Swift 编译器去检查该类的超类(或其中一个父类)是否有匹配重写版本的声明。这个检查可以确保你的重写定义是正确的。
 
 
  访问超类的方法,属性
  通过使用super来访问超类的属性、方法、下标,在方法someMethod的重写实现中,可以通过super.someMethod()来调用超类版本的someMethod方法。在属性someProperty的 getter 或 setter 的重写实现中,可以通过super.someProperty来访问超类版本的someProperty属性。在附属脚本的重写实现中,可以通过super[someIndex]来访问超类版本中的相同下标。
 
1.重写方法
class Car: Vehicle {
var speed: Double = 0.0
init() {
super.init()
maxPassengers =
numberOfWheels =
}
override func description() -> String {
return super.description() + "; "
+ "traveling at \(speed) mph"
}
}
Car声明了一个新的存储型属性speed,它是Double类型的,默认值是0.0,表示“时速是0英里”。Car有自己的初始化器,它将乘客的最大数量设为5,轮子数量设为4。
 
Car重写了继承来的description方法,它的声明与Vehicle中的description方法一致,声明前面加上了override关键字。
 
Car中的description方法并非完全自定义,而是通过super.description使用了超类Vehicle中的description方法,然后再追加一些额外的信息,比如汽车的当前速度。
 
如果你创建一个Car的新实例,并打印description方法的输出,你就会发现描述信息已经发生了改变
let car = Car()
println("Car: \(car.description())")
// Car: 4 wheels; up to 5 passengers; traveling at 0.0 mph
2.重写属性
你可以重写继承来的实例属性或类属性,提供自己定制的getter和setter,或添加属性观察器使重写的属性观察属性值什么时候发生改变。
 
3.重写属性的Getters和Setters
你可以提供定制的 getter(或 setter)来重写任意继承来的属性,无论继承来的属性是存储型的还是计算型的属性。子类并不知道继承来的属性是存储型的还是计算型的,它只知道继承来的属性会有一个名字和类型。你在重写一个属性时,必需将它的名字和类型都写出来。这样才能使编译器去检查你重写的属性是与超类中同名同类型的属性相匹配的。
 
你可以将一个继承来的只读属性重写为一个读写属性,只需要你在重写版本的属性里提供 getter 和 setter 即可。但是,你不可以将一个继承来的读写属性重写为一个只读属性。
 
注意:如果你在重写属性中提供了 setter,那么你也一定要提供 getter。如果你不想在重写版本中的 getter 里修改继承来的属性值,你可以直接返回super.someProperty来返回继承来的值。正如下面的SpeedLimitedCar的例子所示。
 
以下的例子定义了一个新类,叫SpeedLimitedCar,它是Car的子类。类SpeedLimitedCar表示安装了限速装置的车,它的最高速度只能达到40mph。你可以通过重写继承来的speed属性来实现这个速度限制
class SpeedLimitedCar: Car {
override var speed: Double {
get {
return super.speed
}
set {
super.speed = min(newValue, 40.0)
}
}
}
当你设置一个SpeedLimitedCar实例的speed属性时,属性setter的实现会去检查新值与限制值40mph的大小,它会将超类的speed设置为newValue和40.0中较小的那个。这两个值哪个较小由min函数决定,它是Swift标准库中的一个全局函数。min函数接收两个或更多的数,返回其中最小的那个。
 
如果你尝试将SpeedLimitedCar实例的speed属性设置为一个大于40mph的数,然后打印description函数的输出,你会发现速度被限制在40mph:
let limitedCar = SpeedLimitedCar()
limitedCar.speed = 60.0
println("SpeedLimitedCar: \(limitedCar.description())")
// SpeedLimitedCar: 4 wheels; up to 5 passengers; traveling at 40.0 mph
4.重写属性观察器(Property Observer)
你可以在属性重写中为一个继承来的属性添加属性观察器。这样一来,当继承来的属性值发生改变时,你就会被通知到,无论那个属性原本是如何实现的。关于属性观察器的更多内容,请看属性观察器。
 
注意:你不可以为继承来的常量存储型属性或继承来的只读计算型属性添加属性观察器。这些属性的值是不可以被设置的,所以,为它们提供willSet或didSet实现是不恰当。此外还要注意,你不可以同时提供重写的 setter 和重写的属性观察器。如果你想观察属性值的变化,并且你已经为那个属性提供了定制的 setter,那么你在 setter 中就可以观察到任何值变化了。
 
下面的例子定义了一个新类叫AutomaticCar,它是Car的子类。AutomaticCar表示自动挡汽车,它可以根据当前的速度自动选择合适的挡位。AutomaticCar也提供了定制的description方法,可以输出当前挡位。
class AutomaticCar: Car {
var gear =
override var speed: Double {
didSet {
gear = Int(speed / 10.0) +
}
}
override func description() -> String {
return super.description() + " in gear \(gear)"
}
}

当你设置AutomaticCar的speed属性,属性的didSet观察器就会自动地设置gear属性,为新的速度选择一个合适的挡位。具体来说就是,属性观察器将新的速度值除以10,然后向下取得最接近的整数值,最后加1来得到档位gear的值。例如,速度为10.0时,挡位为1;速度为35.0时,挡位为4:

let automatic = AutomaticCar()
automatic.speed = 35.0
println("AutomaticCar: \(automatic.description())")
// AutomaticCar: 4 wheels; up to 5 passengers; traveling at 35.0 mph in gear 4

  

  防止重写

你可以通过把方法,属性或下标标记为final来防止它们被重写,只需要在声明关键字前加上final特性即可。(例如:final var, final func, final class func, 以及 final subscript)
 
如果你重写了final方法,属性或下标,在编译时会报错。在扩展中,你添加到类里的方法,属性或下标也可以在扩展的定义里标记为 final。
 
你可以通过在关键字class前添加@final特性(final class)来将整个类标记为 final 的,这样的类是不可被继承的,否则会报编译错误。

【Swift学习】Swift编程之旅---继承(十七)的更多相关文章

  1. Swift学习——Swift基础具体解释(一)

    版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/zhenyu5211314/article/details/34807025 注:由于基础部分在Swi ...

  2. Swift学习——Swift解释特定的基础(七)

    Implicitly Unwrapped Optionals    隐式解析选项 如上所述.可选意味着常数或变量"没有值".通过可选if声明来推断是否存在值,假设有值析值. 有时候 ...

  3. Swift学习——Swift解释具体的基础(六)

    Optionals    可选 可选(它似乎并不如此翻译)它适用于那些值这种情况可能是空的,有两种情况一个可选:存在值并等于x,要么值不存在. 选配的概念在OC和C里面并没有.在OC中最接近的概念就是 ...

  4. Swift 学习笔记(面向协议编程)

    在Swift中协议不仅可以定义方法和属性,而且协议是可以扩展的,最关键的是,在协议的扩展中可以添加一些方法的默认实现,就是在协议的方法中可以实现一些逻辑,由于这个特性,Swift是可以面向协议进行编程 ...

  5. Swift学习——类的定义,使用,继承,构造等(五)

    Swift学习--类的定义,使用.继承,构造等(五) 类的使用说明 1 使用class和类名来创建一个类名,比如: class student 2 类中属性的声明和常量和变量一样,唯一的差别就是他们的 ...

  6. 记录:swift学习笔记1-2

    swift还在不断的更新做细微的调整,都说早起的鸟儿有虫吃,那么我们早点出发吧,趁着国内绝大多数的coder们还没有开始大范围普遍应用. 网上有些大神说:swift很简单!我不同意这个观点,假如你用h ...

  7. swift学习笔记4——扩展、协议

    之前学习swift时的个人笔记,根据github:the-swift-programming-language-in-chinese学习.总结,将重要的内容提取,加以理解后整理为学习笔记,方便以后查询 ...

  8. swift学习笔记3——类、结构体、枚举

    之前学习swift时的个人笔记,根据github:the-swift-programming-language-in-chinese学习.总结,将重要的内容提取,加以理解后整理为学习笔记,方便以后查询 ...

  9. iOS ---Swift学习与复习

    swift中文网 http://www.swiftv.cn http://swifter.tips/ http://objccn.io/ http://www.swiftmi.com/code4swi ...

随机推荐

  1. [.NET领域驱动设计实战系列]专题八:DDD案例:网上书店分布式消息队列和分布式缓存的实现

    一.引言 在上一专题中,商家发货和用户确认收货功能引入了消息队列来实现的,引入消息队列的好处可以保证消息的顺序处理,并且具有良好的可扩展性.但是上一专题消息队列是基于内存中队列对象来实现,这样实现有一 ...

  2. 关于使用ABP框架搭建的项目升级时需要注意的问题汇总

    ABP理论学习总目录 一步一步使用ABP框架搭建正式项目系列教程 ABP之Module-Zero学习目录 本篇目录 说明 升级方法 问题_01:Log4Net导致编译不成功 2015/12/18更新 ...

  3. 算法:Astar寻路算法改进

    早前写了一篇<RCP:gef智能寻路算法(A star)> 出现了一点问题. 在AStar算法中,默认寻路起点和终点都是N x N的方格,但如果用在路由上,就会出现问题. 如果,需要连线的 ...

  4. 用avalon实现一个完整的todomvc(带router)

    照着todomvc官网的例子,做了一个avalon版的todos,功能全都有了,而且加了router模块,比司徒大大写的都完善(≧▽≦)/~ js文件整整100行,初次使用avalon,书写过程中绕了 ...

  5. MFC CString::GetBuffer() 内存数据异常

    问题描述 在项目中的一个文件路径存储在CString的对象中,这个对象在函数间传递了几次,当传递出来的时候,因为要使用到字符指针,所以GetBuffer获取字符串的指针,但是通过调试,发现,CStri ...

  6. java 堆栈分析3

    很多方式,比如jconsole.jvisualvm,或者jstack -as 这样的形式, 都可以看到实时的java堆栈的变化: eden suvirried0 suvirried1 old perg ...

  7. 第二天 Linux常见命令

    复习: 判断题 1.fedora.redhat.Centos.suse.ubuntu.都是常见的linux 2./分区.swap分区./boot分区都是linux的必须分区 3./dev/sda5在l ...

  8. Atitit  java jsp 新的tag技术

    Atitit  java jsp 新的tag技术 1.1.  Tag Files  vs 原生写 SimpleTag 比较麻烦的 JSP 1.x 允许 Web 开发人员创建 Java 组件(称为标记处 ...

  9. 让自己成为合格的IT员

        2016年10月27日,正式加入了IT天启网络公司,从今天开始就意味着我要正式进军IT行业了.      虽然是为期四个半月的培训,我相信我能够我一定可以在这四个半月的时间里成为一个合格的.优 ...

  10. VS报错:The build tools for v140 (Platform Toolset = 'v140') cannot be found

    VS低版本打开高版本常会出现的错: The build tools for v140 (Platform Toolset = 'v140') cannot be found. To build usi ...