关于继承中的构造规则是一个难点。

假设有问题,请留言问我。

我的Swift新手教程专栏

http://blog.csdn.net/column/details/swfitexperience.html

为什么要有构造器:为类中自身和继承来的存储属性赋初值。

一、两种构造器-指定构造器和便利构造器

指定构造器:类中必备的构造器。为全部的属性赋初值。(有些子类可能不须要显示声明,由于默认从基类继承了)

便利构造器:类中的辅助构造器,通过调用指定构造器为属性赋初值。(仅在必要的时候声明)

举例

class Food {
var name: String
init(name: String) {
self.name = name
}
convenience init() {
self.init(name: "[Unnamed]")
}
}

便利构造器通过conveniencekeyword声明,能够看到。便利构造器是通过调用指定构造器来进行构造的。这也就是一个关键的概念:横向代理。

何为代理:就是让别人帮你干活

二、构造过程中的规则

(一)构造器链就是调用构造器的顺序

规则例如以下:

1.1、指定构造器必须调用其父类的指定构造器

1.2、便利构造器必须调用同一类中的指定构造器

1.3、便利构造器必须最后以调用一个指定构造器而结束

总得来说一句话:便利构造器横向代理,指定构造器向上代理。

举个样例:

class Base{
var baseVar:String
init(baseInput:String){
baseVar = baseInput
}
convenience init(){
self.init(baseInput:"")
}
}
class Sub:Base{
var subVar:String;
init(subInput:String,baseInput:String){
subVar = subInput
super.init(baseInput:baseInput)//这里是规则1.1
}
convenience init(conSubInput:String){
self.init(subInput:conSubInput,baseInput:"")//这里是规则1.2
}
convenience init(){
self.init(conSubInput:"")//这里是规则1.3,由于调用了另外一个便利构造器,而另外一个便利构造器以调用指定构造器结束
}
}

(二)关于构造器的继承与重载

swift中,子类不会默认继承父类的构造器。

构造器的重载遵循构造器链的规则(1.1-1.3)

构造器的继承规则例如以下:

2.1、假设子类中未定义不论什么指定构造器,将会自己主动继承全部父类的指定构造器

2.2、假设子类中提供了全部父类指定构造器,无论是通过规则2.1继承来的,还是自己定义实现的,它将继承全部父类的便利构造器。

注意:子类能够通过部分满足规则2.2的方式,使用子类便利构造器来实现父类的指定构造器。

样例一:

class Base{
var baseVar:String
init(baseInput:String){
baseVar = baseInput
}
convenience init(){
self.init(baseInput:"basevar")
}
}
class Sub:Base{
var subVar:String = "subvar";
}

这里子类未定义不论什么构造器,所以满足规则2.1,2.1,将继承全部父类的指定构造器和便利构造器

所以能够这么调用

var instance1 = Sub()
var instance2 = Sub(baseInput:"newBaseVar")

样例二

class Base{
var baseVar:String
init(baseInput:String){
baseVar = baseInput
}
init(firstPart:String,secondPart:String){
baseVar = firstPart + secondPart
}
convenience init(){
self.init(baseInput:"basevar")
}
}
class Sub:Base{
var subVar:String;
init(subInput:String,baseInput:String){
subVar = subInput
super.init(baseInput)
}
}

这里,子类仅仅是实现了父类的一个构造器,所以并未继承便利构造器,也没有继承另外一个指定构造器

仅仅能够这么创造实例

var instance = Sub(subInput:"subvar",baseInput:"basevar")

(三)基于上述两个规则,构造过程分为两个部分

阶段一

  • 某个指定的构造器或者便利构造器被调用;
  • 完毕新实例的内存分配(此时内存尚未初始化)。
  • 指定构造器确保其引入的全部存储属性已经赋值(存储属性极其所属内存完毕初始化)。
  • 指定构造器调用父类构造器(父类构造器属性初始化)。
  • 这个调用父类的构造器沿着构造器链一直向上。直到最顶部。(确保全部的继承的基类过程都已经初始化)。

阶段二

  • 从顶部一直向下。每一个构造器链中类指定的构造器都有机会进一步定制实例。构造器此时能够訪问self,改动它的属性而且调用实例方法等等。
  • 终于,随意构造器的便利构造器将有机会定制实例和使用self。

可能这个规则有点抽象。举个样例就明确了

class Base{
var baseVar:String
init(baseInput:String){
baseVar = baseInput
}
}
class Sub:Base{
var subVar:String;
func subPrint(){
println("如今能够调用实例方法了")
}
init(subInput:String,baseInput:String){
subVar = subInput
super.init(baseInput:baseInput)
//这里就完毕了阶段一
self.subVar = subInput + "123"//此时能够调用self
subPrint()//此时也能够调用实例方法了
}
}

总得来说:当类的实例的内存被初始化完毕,也就是调用super.init()之后,就完毕了阶段一了。



三、编译器的安全检查

检查一


  指定构造器必须在它所在类的属性先初始化完毕后才干把构造任务向上代理给父类中的构造器。简单来说。就是先初始化自己的存储属性,在调用父类的super.init向上初始化

检查二

  指定构造器必须先向上调用父类构造器。在为继承来的属性赋初值。

这个非常简答,如果继承来个x,你先为x赋值为1了,而在调用父类构造器。父类构造器会为x赋另外一个初值来保证初始化过程完毕,那么你赋值的1就被覆盖了

检查三

  便利构造器先调用同类中其它构造器,再为随意属性赋初值。和检查二类似。也是防止被覆盖

检查四

  构造器在第一阶段完毕之前。不能饮用self,不能调用不论什么实例属性,不能调用实例方法





四、总结一下

指定构造器的过程是这种

1、为自己的属性赋初值

2、调用基类构造器(super.init)

3、然后就能够调用self,和实例方法,存储属性。定制新的值了。

然后,我们看下官方文档里给出的一个比較好的样例

class Food {
var name: String
init(name: String) {
self.name = name
}
convenience init() {
self.init(name: "[Unnamed]")
}
}
class RecipeIngredient: Food {
var quantity: Int
init(name: String, quantity: Int) {
self.quantity = quantity
super.init(name: name)
}
override convenience init(name: String) {
self.init(name: name, quantity: 1)
}
}
class ShoppingListItem: RecipeIngredient {
var purchased = false
var description: String {
var output = "\(quantity) x \(name.lowercaseString)" {
output += purchased ? " YES" : " NO"
return output
}
}

这个构造器链的关系如图



解释

  • 基类Food定义了一个指定构造函数和一个便利构造器
  • 子类RecipeIngredient实现了基类Food全部的指定构造器。所以它继承了基类的便利构造器
  • 子类ShoppingListItem未定义构造器,所以继承了基类RecipeIngredient的全部构造器。Swift入门系列15-继承中的构造规则(难点)

Swift难点-继承中的构造规则实例具体解释的更多相关文章

  1. C++ 类的继承三(继承中的构造与析构)

    //继承中的构造与析构 #include<iostream> using namespace std; /* 继承中的构造析构调用原则 1.子类对象在创建时会首先调用父类的构造函数 2.父 ...

  2. C++学习笔记-继承中的构造与析构

    C++存在构造函数与析构函数,继承中也存在构造和析构函数.继承中的构造和析构函数与普通的构造析构有细微差别. 赋值兼容性原则 #include "iostream" using n ...

  3. C++继承中的构造和析构

    1,构造:对象在创建的后所要做的一系列初始化的工作: 析构:对象在摧毁之前所要做的一系列清理工作: 2,思考: 1,子类中如何初始化父类成员? 1,对于继承而言,子类可以获得父类的代码,可以获得父类中 ...

  4. C++语法小记---继承中的构造和析构顺序

    继承中构造和析构的顺序 先父母,后客人,最后自己 静态变量和全局变量在最开始 析构和构造的顺序完全相反 #include <iostream> #include <string> ...

  5. 【Java学习笔记之二十二】解析接口在Java继承中的用法及实例分析

    一.定义 Java接口(Interface),是一系列方法的声明,是一些方法特征的集合,一个接口只有方法的特征没有方法的实现,因此这些方法可以在不同的地方被不同的类实现,而这些实现可以具有不同的行为( ...

  6. C++ //继承中构造和析构顺序

    1 #include <iostream> 2 #include <string> 3 using namespace std; 4 5 class Base 6 { 7 pu ...

  7. C++类继承中,基类/当前对象属性/当前对象的构造顺序

    [1]中提到,规范的派生类构造函数三个要点: 首先创建基类对象 应通过成员初始化列表,创建基类对象 应该初始化本派生类新增的成员变量 那在构造派生类实例的过程中,其基类(以及多继承的时候多个基类)/当 ...

  8. 前端知识体系:JavaScript基础-原型和原型链-理解 es6 中class构造以及继承的底层实现原理

    理解 es6 中class构造以及继承的底层实现原理 原文链接:https://blog.csdn.net/qq_34149805/article/details/86105123 1.ES6 cla ...

  9. Android(java)学习笔记119:继承中父类没有无参构造

    /* 如果父类没有无参构造方法,那么子类的构造方法会出现什么现象呢? 报错. 如何解决呢? A:在父类中加一个无参构造方法 B:通过使用super关键字去显示的调用父类的带参构造方法 C:子类通过th ...

随机推荐

  1. MFC实现多风格真彩色大图标工具栏按钮

    研究zlib库,想实现一个类似winrar功能的小东东,打开winrar界面看它的工具栏比较好看于是动手想做一个,当然资源也使用的是winrar附带的.下面是截图:真彩色(32位)32*32大图标工具 ...

  2. HTML5动态分页效果代码

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  3. data URI scheme及其应用

    data URI scheme通俗的来讲就是将一张图片直接塞到HTML中而不是通过HTTP请求去获取.这样从表面上看会降低一次HTTP的请求,实现了对于网页的优化(只是看了其它一些文章data URI ...

  4. ThinkPHP 的模型使用对数据库增删改查(五)

    原文:ThinkPHP 的模型使用对数据库增删改查(五) ThinkPHP 的模型使用 // 直接连接数据库,但是得先去配置文件中配置下才行 class IndexAction extends Act ...

  5. 关于Oralce数据库优化的几点总结

    个人理解,数据库性能最关键的因素在于IO,因为操作内存是快速的,但是读写磁盘是速度很慢的,优化数据库最关键的问题在于减少磁盘的IO,就个人理解应该分为物理的和逻辑的优化, 物理的是指oracle产品本 ...

  6. JavaScript 中的事件流和事件处理程序(读书笔记思维导图)

    JavaScript 程序采用了异步事件驱动编程模型.在这种程序设计风格下,当文档.浏览器.元素或与之相关的对象发生某些有趣的事情时,Web 浏览器就会产生事件(event). JavaScript ...

  7. The tempfile module

    The tempfile module The tempfile module This module allows you to quickly come up with unique names ...

  8. Python 实现的下载op海贼王网的图片(网络爬虫)

    没得事就爬一下我喜欢的海贼王上的图片 须要在d盘下建立一个imgcache目录 # -*- coding: utf-8 -*- import urllib import urllib2 import ...

  9. VS2010调用VLFeat

    相比OpenCV,VLFeat的代码全是开源,并且非常重要的一点,事实上现的sift和Low的精度差点儿相同,这个团队全是码神,膜拜一下. 依照以下的网址进行安装,本人已经装上了,确实能够的. 安装參 ...

  10. centos5.5字体为方块问题的解决_深入学习编程_百度空间

    centos5.5字体为方块问题的解决_深入学习编程_百度空间 centos5.5字体为方块问题的解决 一.yum -y install fonts-chinese二.yum -y install f ...