Swift—默认构造函数-备
结构体和类的实例在构造过程中会调用一种特殊的init方法,称为构造函数。构造函数没有返回值,可以重载。在多个构造函数重载的情况下,运行环境可以根据它的外部参数名或参数列表调用合适的构造函数。
默认构造函数
结构体和类在构造过程中会调用一个构造函数,即便是没有编写任何构造函数,编译器也会提供一个默认的构造函数。下面看示例代码:
- class Rectangle {
- var width: Double = 0.0
- var height: Double = 0.0
- }
- var rect = Rectangle() //创建实例,并调用默认构造函数init()
- rect.width = 320.0
- rect.height = 480.0
- print("长方形:\(rect.width) x \(rect.height)")
- Rectangle()表示调用了某个方法,这个方法就是默认构造函数init()。
- 事实上,在Rectangle的定义过程中省略了构造函数,相当于如下代码:
- class Rectangle {
- var width: Double = 0.0
- var height: Double = 0.0
- init() {
- }
- }
如果Rectangle是结构体,则它的定义如下:
struct Rectangle {
var width: Double = 0.0
var height: Double = 0.0
}
而结构体Rectangle的默认构造函数与类Rectangle的默认构造函数是不同的,相当于如下代码:
- struct Rectangle {
- var width: Double = 0.0
- var height: Double = 0.0
- init() {
- }
- init(width: Double, height: Double) { //有参数的构造函数
- self.width = width
- self.height = height
- }
- }
要调用哪个构造函数是根据传递的参数名和参数类型决定的。
在构造函数中可以使用构造函数代理帮助完成部分构造工作。类构造函数代理分为横向代理和向上代理,横向代理只能在发生在同一类内部,这种构造函数称为便利构造函数。向上代理发生在继承的情况下,在子类构造过程中,要先调用父类构造函数初始化父类的存储属性,这种构造函数称为指定构造函数。
构造函数调用规则
- Person和Student类示例:
- class Person {
- var name: String
- var age: Int
- func description() -> String {
- return "\(name) 年龄是: \(age)"
- }
- convenience init () { //便利构造函数
- self.init(name: "Tony")
- self.age = 18
- }
- convenience init (name: String) { //便利构造函数
- self.init(name: name, age: 18)
- }
- init (name: String, age: Int) { //指定构造函数
- self.name = name
- self.age = age
- }
- }
- class Student: Person {
- var school: String
- init (name: String, age: Int, school: String) { //指定构造函数
- self.school = school
- super.init(name: name, age: age)
- }
- convenience override init (name: String, age: Int) {//便利构造函数
- self.init(name: name, age: age, school: "清华大学")
- }
- }
- let student = Student()
- print("学生: \(student.description())")
构造函数之间的调用形成了构造函数链,如图所示。
Swift限制构造函数之间的代理调用的规则有3条,如下所示。
指定构造函数必须调用其直接父类的的指定构造函数。从图可见,Student中的④号指定构造函数调用Person中的③号指定构造函数。
便利构造函数必须调用同一类中定义的其他构造函数。从图可见,Student中的⑤号便利构造函数调用同一类中的④号便利构造函数,Person中的①号便利构造函数调用同一类中的②号便利构造函数。
便利构造函数必须最终以调用一个指定构造函数结束。从图可见,Student中的⑤号便利构造函数调用同一类中的④号指定构造函数,Person中的②号便利构造函数调用同一类中的③号指定构造函数。
- ==================================================
Swift中的子类构造函数的来源有两种:自己编写和从父类继承。并不是父类的所有的构造函数都能继承下来,能够从父类继承下来的构造函数是有条件的,如下所示。
条件1:如果子类没有定义任何指定构造函数,它将自动继承所有父类的指定构造函数。
条件2:如果子类提供了所有父类指定构造函数的实现,无论是通过条件1继承过来的,还是通过自己编写实现的,它都将自动继承所有父类的便利构造函数。
下面看示例代码:
- class Person {
- var name: String
- var age: Int
- func description() -> String {
- return "\(name) 年龄是: \(age)"
- }
- convenience init () {
- self.init(name: "Tony")
- self.age = 18
- }
- convenience init (name: String) {
- self.init(name: name, age: 18)
- }
- init (name: String, age: Int) {
- self.name = name
- self.age = age
- }
- }
- class Student: Person {
- var school: String
- init (name: String, age: Int, school: String) {
- self.school = school
- super.init(name: name, age: age)
- }
- convenience override init (name: String, age: Int) {
- self.init(name: name, age: age, school: "清华大学")
- }
- }
- class Graduate: Student {
- var special: String = ""
- }
来看看符合条件1的继承,Graduate继承Student,Graduate类没有定义任何指定构造函数,它将自动继承所有Student的指定构造函数。符合条件1后,Graduate从Student继承了如下指定构造函数:
init (name: String, age: Int,school: String)
再看符合条件2的继承,由于Graduate实现了Student的所有指定构造函数,Graduate将自动继承所有Student的便利构造函数。符合条件2后,Graduate从Student继承了如下3个便利构造函数:
init (name: String, age: Int)
init (name: String)
init ()
Student继承Person后有4个构造函数。
条件1对Student不满足,因为它有指定构造函数,Student类中的便利构造函数init (name: String, age: Int)满足了条件2,它实现了父类指定构造函数init (name: String, age: Int)。另外,由于子类构造函数与父类构造函数参数相同,需要使用override关键字,表示子类构造函数重写(overriding)了父类构造函数。
由于Student类实现了父类指定构造函数,因此也继承了父类的另外两个便利构造函数。
Swift—默认构造函数-备的更多相关文章
- 《从零开始学Swift》学习笔记(Day 37)——默认构造函数
原创文章,欢迎转载.转载请注明:关东升的博客 结构体和类的实例在构造过程中会调用一种特殊的init方法,称为构造函数.构造函数没有返回值,可以重载.在多个构造函数重载的情况下,运行环境可以根据它的外部 ...
- C++的默认构造函数与构造函数
今天看书,忽然发现自己对默认构造函数/构造函数的理解很模糊,在实际项目中写类时,这些细节问题并没有涉及到.因此,就专门对着<C++ Primer Plus>将默认构造函数/构造函数这一块简 ...
- C++ 合成默认构造函数的真相
对于C++默认构造函数,我曾经有两点误解: 类如果没有定义任何的构造函数,那么编译器(一定会!)将为类定义一个合成的默认构造函数. 合成默认构造函数会初始化类中所有的数据成员. 第一个误解来自于我学习 ...
- C++中默认构造函数中数据成员的初始化
构造函数的任务是初始化数据成员的,在类中,如果没有显示定义任何构造函数,编译器将为我们创建一个构造函数,称为合成的默认构造函数,合成的默认构造函数使用与变量初始化相同的规则来初始化成员.即当类中的数据 ...
- [C++]默认构造函数
默认构造函数(default constructor)就是在没有显示提供初始化式时调用的构造函数.它由不带参数的构造函数,或者为所有的形参提供默认实参的构造函数定义.若个定义某个类的变量时没有提供初始 ...
- 【C++对象模型】构造函数语意学之一 默认构造函数
默认构造函数,如果程序员没有为类定义构造函数,那么编译器会在[需要的时候]为类合成一个构造函数,而[需要的时候]分为程序员需要的时候和编译器需要的时候,程序员需要的时候应该由程序员来做工作,编译器需要 ...
- C++关于编译器合成的默认构造函数
有两个常见的误解: 1.任何类如果没有定义默认构造函数,就会被合成出一个来. 2.编译器合成的默认构造函数会显式地设定类内每一个数据成员的默认值. 对于第一个误解,并不是任何类在没有显式定义默认构造函 ...
- C++默认构造函数的一点说明
大多数C++书籍都说在我们没有自己定义构造函数的时候,编译器会自动生成默认构造函数.其实这句话我一直也是 深信不疑.但是最近看了一些资料让我有了一点新的认识. 其实我觉得大多数C++书籍之所以这样描述 ...
- C++结构体:默认构造函数,复制构造函数,重载=运算符
C++结构体提供了比C结构体更多的功能,如默认构造函数,复制构造函数,运算符重载,这些功能使得结构体对象能够方便的传值. 比如,我定义一个简单的结构体,然后将其作为vector元素类型,要使用的话,就 ...
随机推荐
- Java 8 中新的 Date 和 Time 类入门详解
这篇文章主要是java8中新的Date和Time API的实战.新的Date和Time类是java开发者社区千呼万唤始出来的.Java8 之前存在的Date类一直都受人诟病,很多人都会选择使用第三方的 ...
- Java8 时间 API
前言 Java8 中最为人津津乐道的新改变恐怕当属函数式 API 的加入.但实际上,Java8 所加入的新功能远不止这个. 本文将基于<Java SE8 for the Really Impat ...
- Tomcat中server.xml配置及Context的配置说明
server.xml配置简介 下面是这个文件中的基本配置信息,更具体的配置信息见tomcat的文档 server: port 指定一个端口,这个 ...
- BootStrap--Tables(表格) MVC中不刷新做增,删,改(C#)
自带的Tables会有自动分页,搜索等一些动能,很方便,唯一的不足就是添加,修改,删除数据需要刷新页面,并不能静态. 下面说的是如何不刷新页面(Ajax)去执行增,删,改操作. 需要用到的样式,JS库 ...
- 利用PyQt4写的小工具软件
应公司文职工作人员需求,写一个车间人员工作时间的统计软件,输入开始工作时间1,再输入结束工作时间2,计算两个时间的差值. 根据需求,初步构想的UI界面如下: 下面开始干活. 分析后觉得利用PyQt4来 ...
- HDU3631:Shortest Path(Floyd)
Problem Description When YY was a boy and LMY was a girl, they trained for NOI (National Olympiad in ...
- SQL基础--> 约束(CONSTRAINT)
--============================= --SQL基础--> 约束(CONSTRAINT) --============================= 一.几类数据完 ...
- [Protractor] Testing With Protractor Page Objects
Protractor Page Objects are a recommended for testing your AngularJS applications. Page Objects abst ...
- 基于AE的SimpleGIS框架的搭建
ArcGIS是Esri公司集40余年地理信息系统(GIS)咨询和研发经验,奉献给用户的一套完整的GIS平台产品,具有强大的地图制作.空间数据管理.空间分析.空间信息整合.发布与共享的能力.本人主要就A ...
- react.js 你应知道的9件事
React.js 初学者应该知道的 9 件事 本文假定你已经有了一下基本的概念.如果你不熟悉 component.props 或者 state 这些名词,你最好先去阅读下官方起步和手册.下面的代码 ...