余晖落尽暮晚霞,黄昏迟暮远山寻
本站
当前位置:网站首页 > 编程知识 > 正文

Swift 4.1 官方文档大全(第十三章)继承(Inheritance)

xiyangw 2022-12-03 13:36 14 浏览 0 评论

继承

一个类可以继承另一个类的方法,属性和其他特征。 当一个类从另一个类继承时,继承类被称为子类,并且它继承的类被称为它的超类。 继承是区分Swift中的其他类型的基本行为。

Swift 4.1 官方文档大全(第十三章)继承(Inheritance)

Swift中的类可以调用和访问属于它们超类的方法,属性和下标,并且可以提供它们自己的覆盖版本的这些方法,属性和下标以改进或修改它们的行为。 Swift通过检查覆盖定义是否具有匹配的超类定义来帮助确保覆盖是正确的。

类还可以将属性观察器添加到继承的属性中,以便在属性值更改时得到通知。 属性观察者可以被添加到任何属性,而不管它最初是否被定义为存储属性或计算属性。

定义一个基类

任何不从另一个类继承的类都称为基类。

注意

Swift类不会从通用基类继承。 您在未指定超类的情况下定义的类自动成为基础类,供您进行构建。

下面的例子定义了一个名为Vehicle的基类。 此基类定义一个名为currentSpeed的存储属性,默认值为0.0(推断Double属性类型)。 currentSpeed属性的值由称为description的只读计算String属性使用,以创建车辆的描述。

Vehicle基类还定义了一个名为makeNoise的方法。 此方法实际上对基础Vehicle实例不做任何操作,但稍后将由Vehicle的子类自定义:

class Vehicle {

var currentSpeed = 0.0

var description: String {

return "traveling at \(currentSpeed) miles per hour"

}

func makeNoise() {

// do nothing - an arbitrary vehicle doesn't necessarily make a noise

}

}

使用初始值设定语句创建Vehicle的新实例,该实例的类型名称后跟空括号:

let someVehicle = Vehicle()

创建了一个新的Vehicle实例后,您可以访问其描述属性以打印车辆当前速度的可读描述:

print("Vehicle: \(someVehicle.description)")

// Vehicle: traveling at 0.0 miles per hour

Vehicle类定义了任意车辆的共同特征,但本身并没有多大用处。 为了使其更有用,您需要对其进行改进以描述更具体的车辆类型。

子类

子类是基于现有类的新类的行为。 子类继承现有类的特征,然后可以对其进行优化。 您还可以向子类添加新的特征

为了表明子类具有超类,请在超类名称前面写入子类名称,并用冒号分隔:

class SomeSubclass: SomeSuperclass {

// subclass definition goes here

}

以下示例定义了一个名为Bicycle的子类,其中包含Vehicle的超类:

class Bicycle: Vehicle {

var hasBasket = false

}

新的Bicycle类会自动获得Vehicle的所有特性,例如其当前速度和描述属性及其makeNoise()方法。

除了它继承的特征之外,Bicycle类定义了一个新的存储属性hasBasket,其默认值为false(推断属性的Bool类型)。

默认情况下,您创建的任何新的Bicycle实例都不会有篮子。 创建该实例后,您可以将hasBasket属性设置为true:

let bicycle = Bicycle()

bicycle.hasBasket = true

您还可以修改Bicycle实例的继承的currentSpeed属性,并查询实例的继承描述属性:

bicycle.currentSpeed = 15.0

print("Bicycle: \(bicycle.description)")

// Bicycle: traveling at 15.0 miles per hour

子类本身可以被分类。 下一个例子为称为“串联”的双座自行车创建了Bicycle的子类:

class Tandem: Bicycle {

var currentNumberOfPassengers = 0

}

Tandem继承了Bicycle的所有属性和方法,继而继承了Vehicle的所有属性和方法。 Tandem子类还添加了一个名为currentNumberOfPassengers的新存储属性,默认值为0。

如果您创建了Tandem实例,则可以使用它的任何新的和继承的属性,并查询它从Vehicle继承的只读描述属性:

let tandem = Tandem()

tandem.hasBasket = true

tandem.currentNumberOfPassengers = 2

tandem.currentSpeed = 22.0

print("Tandem: \(tandem.description)")

// Tandem: traveling at 22.0 miles per hour

重写

一个子类可以提供它自己的自定义实现,它实际上是从超类继承的实例方法,类型方法,实例属性,类型属性或下标。这被称为重写(覆盖)。

要覆盖会被继承的特性,可以使用override关键字为您的覆盖定义添加前缀。这样做明确说明您打算提供覆盖并且没有提供错误的匹配定义。意外覆盖可能会导致意外的行为,并且在编译代码时,没有覆盖关键字的覆盖将被诊断为错误。

override关键字还会提示Swift编译器检查您的重写类的超类(或其父类之一)是否具有与您为重写提供的声明相匹配的声明。此检查可确保您的覆盖定义是正确的

访问超类方法,属性和下标

当您为子类提供方法,属性或下标覆盖时,使用现有的超类实现作为覆盖的一部分有时很有用。例如,您可以改进现有实现的行为,或将修改后的值存储在现有的继承变量中。

在适当的情况下,您可以使用 supe r前缀访问方法,属性或下标的超类版本:

重写的方法someMethod()可以通过在覆盖的方法实现中调用super.someMethod()来调用someMethod()的超类版本。

被重写的属性someProperty可以在重载的getter或setter实现中作为super.someProperty访问someProperty的超类版本。

someIndex的重写下标可以从重写的下标实现中访问与super [someIndex]相同的下标的超类版本。

重写方法

您可以重写继承的实例或类型方法,以在您的子类中提供该方法的定制或替代实现。

以下示例定义了一个名为Train的Vehicle的新子类,它覆盖了Train从Vehicle继承的makeNoise()方法:

classTrain: Vehicle {

override func makeNoise() {

print("Choo Choo")

}

}

如果您创建了Train的新实例并调用了它的makeNoise()方法,您可以看到该方法的Train子类版本被调用:

let train = Train()

train.makeNoise()

// Prints "Choo Choo"

重写属性

您可以覆盖继承的实例或类型属性以为该属性提供您自己的自定义getter和setter,或者添加属性观察器以使重写属性能够观察基础属性值何时更改。

重写属性getter和setter

无论继承的属性是作为源存储还是计算属性实现的,您都可以提供自定义getter(和setter,如果适用)覆盖任何继承的属性。继承属性的存储或计算性质不为子类所知 - 它只知道继承属性具有特定的名称和类型。您必须始终声明您正在覆盖的属性的名称和类型,以使编译器能够检查您的覆盖是否与具有相同名称和类型的超类属性相匹配。

您可以通过在子类属性覆盖中提供getter和setter来呈现继承的只读属性作为读写属性。但是,您不能将继承的读写属性显示为只读属性

注意

如果您提供一个setter作为属性重写的一部分,则还必须为该重写提供一个getter。如果您不想在重写的getter中修改继承的属性值,则可以通过从getter返回super.someProperty来传递继承的值,其中someProperty是您正在覆盖的属性的名称

以下示例定义了一个名为Car的新类,它是Vehicle的一个子类。 Car类引入了一个名为gear的新存储属性,默认整数值为1. Car类也覆盖它从Vehicle继承的description属性,以提供包含当前齿轮的自定义描述:

class Car: Vehicle {

var gear = 1

override var description: String {

return super.description + " in gear \(gear)"

}

}

描述属性的重写通过调用super.description开始,后者返回Vehicle类的描述属性。 Car类的说明版本会在本说明的最后添加一些额外的文字,以提供有关当前档位的信息。

如果您创建Car类的实例并设置其齿轮和currentSpeed属性,则可以看到其描述属性返回在Car类中定义的定制描述:

let car = Car()

car.currentSpeed = 25.0

car.gear = 3

print("Car: \(car.description)")

// Car: traveling at 25.0 miles per hour in gear 3

重写属性观察器

您可以使用属性重写来将属性观察器添加到继承的属性。这使您可以在继承属性的值发生更改时得到通知,而不管该属性最初是如何实现的。

注意

您不能将属性观察器添加到继承的常量存储属性或继承的只读计算属性。这些属性的值不能被设置,因此提供willSet或didSet实现作为覆盖的一部分是不合适的。

还要注意,你不能同时为同一个属性提供重写的setter和重写属性观察者。如果您想观察对属性值的更改,并且您已经为该属性提供了自定义设置器,则可以简单地观察自定义设置器中的任何值更改。

以下示例定义了一个名为AutomaticCar的新类,它是Car的一个子类。 AutomaticCar类表示带有自动变速箱的汽车,该变速箱根据当前速度自动选择适合的档位:

class AutomaticCar: Car {

override var currentSpeed: Double {

didSet {

gear = Int(currentSpeed / 10.0) + 1

}

}

}

无论何时设置AutomaticCar实例的currentSpeed属性,属性的didSet观察者都会将实例的齿轮属性设置为适合新速度的齿轮选择。 具体来说,属性观察者选择一个新的当前速度值除以10的齿轮,向下舍入到最接近的整数加1.速度35.0产生齿轮4:

let automatic = AutomaticCar()

automatic.currentSpeed = 35.0

print("AutomaticCar: \(automatic.description)")

// AutomaticCar: traveling at 35.0 miles per hour in gear 4

防止覆盖

您可以通过将方法,属性或脚标标记为final来防止方法,属性或脚标被覆盖。 通过在method,property或subscript的introducer关键字(如final var,final func,final class func和final subscript)之前写入最终修饰符来完成此操作。

任何试图覆盖子类中的最终方法,属性或下标的尝试都会报告为编译时错误。 您在扩展中添加到类中的方法,属性或下标也可以在扩展的定义中标记为final。

您可以通过在其类定义(final类)中的class关键字之前写入final修饰符来将整个类标记为final。 任何对最终类进行子类化的尝试都会报告为编译时错误。

相关推荐

Vue的框架(了解)

前端MVC设计模式MVC设计模式,其实就是将前端实现某个业务的所有代码划分为三部分Model:模型,指数据模型,这个数据一般来自于服务器View:视图,指页面标签内容Controller:控制...

Vue.js实战 第五章练习一

练习要求:在原有表格基础上,新增一项是否选中该商品的功能,总价变为只计算选中商品的总价,同时提供一个全选的按钮。实现思路:按照vue数据和dom元素双向绑定的特性,定义allCheckStatus变量...

Vue基础到进阶教程之class和style绑定

关于class和style我们并不陌生,这个在学习css的时候就是家常便饭了,操作元素的class列表和内联样式是数据绑定的一个常见需求。因为它们都是属性,所以我们可以用v-bind处理它们,...

深入Vue 必学高阶组件 HOC「进阶篇」

作者:ssh转发连接:https://mp.weixin.qq.com/s/seKoLSIMtTd1sU4uDrgZCA前言高阶组件这个概念在React中一度非常流行,但是在Vue的社区里讨论...

周末大礼包,23道高质量中级前端面试题。金九银十,建议收藏

这套面试题考察的内容比较常见,涉及到JavaScript、ES6、CSS、Vue、简单算法,浏览器相关知识等。题目列表1.JavaScript的数据类型有哪些2.什么是同源策略3.跨域的方法...

vue3.0-摒弃Object.defineProperty,基于 Proxy 的观察者机制

写在前面:11月16日早上,Vue.js的作者尤大大在VueToronto的主题演讲中预演了Vue.js3.0的一些新特性,其中一个很重要的改变就是Vue3将使用ES6的Proxy作...

程序员都必掌握的前端教程之VUE基础教程(七)

阅读本文约需要10分钟,您可以先关注我们,避免下次无法找到。本篇文章成哥继续带大家来学习前端VUE教程,今天主要讲解VUE的表单处理等知识点。下面我们就一起来学习该块内容吧!01简介在日常开发中,我...

web前端开之网站搭建框架之vue详解

网站搭建框架之vueVue是web前端快速搭建网站的框架之一。它与jQuery有所不同,是以数据驱动web界面(以操作数据改变页面,而jQuery是以操作节点来改变页面),同时,vue还实现了数据的双...

vue3.0尝鲜-基于 Proxy 的观察者机制探索

Vue.js的作者尤大大在VueToronto的主题演讲中预演了Vue.js3.0的一些新特性,其中一个很重要的改变就是Vue3将使用ES6的Proxy作为其观察者机制,取代之前使用...

TypeScript 设计模式之观察者模式

一、模式介绍1.背景介绍在软件系统中经常碰到这类需求:当一个对象的状态发生改变,某些与它相关的对象也要随之做出相应的变化。这是建立一种「对象与对象之间的依赖关系」,一个对象发生改变时将「自动通知其他...

vue面试3

1.单页面应用与多页面应用的去别2.简述一下Sass、Less,且说明区别?他们是动态的样式语言,是CSS预处理器,CSS上的一种抽象层。他们是一种特殊的语法/语言而编译成CSS。变量符不一样,les...

VUE v-bind 数据绑定

动态的绑定一个或多个attribute,也可以是组件的prop。缩写::或者.(当使用.prop修饰符)期望:any(带参数)|Object(不带参数)参数:attrOrP...

vue初学习之自定义选择框实现

v-model简单介绍在使用vue的过程中会经常用到input和textarea这类表单元素,vue对于这些元素的数据绑定和我们以前经常用的jQuery有些区别。vue使用v-model实现这些标签...

Vue实现拖拽穿梭框功能四种方式

一、使用原生js实现拖拽打开视频讲解更加详细Vue实现拖拽穿梭框功能的四种方式_哔哩哔哩_bilibili<html><head><meta...

Vue3.x setup 语法糖实现props双向绑定

1.背景为了封装一下Element-Plus的分页插件,需要实现父子组件之间的传值。2.父组件<scriptsetuplang="ts">letqueryPa...

取消回复欢迎 发表评论: