结构体和类的实例在构造过程中会调用一种特殊的init方法,称为构造函数。构造函数没有返回值,可以重载。在多个构造函数重载的情况下,运行环境可以根据它的外部参数名或参数列表调用合适的构造函数。
默认构造函数
结构体和类在构造过程中会调用一个构造函数,即便是没有编写任何构造函数,编译器也会提供一个默认的构造函数。下面看示例代码:

  1. class Rectangle {
  2. var width: Double  = 0.0
  3. var height: Double = 0.0
  4. }
  5. var rect = Rectangle()   //创建实例,并调用默认构造函数init()
  6. rect.width = 320.0
  7. rect.height = 480.0
  8. print("长方形:\(rect.width) x \(rect.height)")
  9. Rectangle()表示调用了某个方法,这个方法就是默认构造函数init()。
  10. 事实上,在Rectangle的定义过程中省略了构造函数,相当于如下代码:
  11. class Rectangle {
  12. var width: Double  = 0.0
  13. var height: Double = 0.0
  14. init() {
  15. }
  16. }

如果Rectangle是结构体,则它的定义如下:
struct Rectangle {
    var width: Double = 0.0
    var height: Double = 0.0
}
而结构体Rectangle的默认构造函数与类Rectangle的默认构造函数是不同的,相当于如下代码:

  1. struct Rectangle {
  2. var width: Double = 0.0
  3. var height: Double = 0.0
  4. init() {
  5. }
  6. init(width: Double, height: Double) { //有参数的构造函数
  7. self.width   = width
  8. self.height  = height
  9. }
  10. }

要调用哪个构造函数是根据传递的参数名和参数类型决定的。

在构造函数中可以使用构造函数代理帮助完成部分构造工作。类构造函数代理分为横向代理和向上代理,横向代理只能在发生在同一类内部,这种构造函数称为便利构造函数。向上代理发生在继承的情况下,在子类构造过程中,要先调用父类构造函数初始化父类的存储属性,这种构造函数称为指定构造函数。

构造函数调用规则

  1. Person和Student类示例:
  2. class Person {
  3. var name: String
  4. var age: Int
  5. func description() -> String {
  6. return "\(name) 年龄是: \(age)"
  7. }
  8. convenience init () {         //便利构造函数
  9. self.init(name: "Tony")
  10. self.age = 18
  11. }
  12. convenience init (name: String) { //便利构造函数
  13. self.init(name: name, age: 18)
  14. }
  15. init (name: String, age: Int) {       //指定构造函数
  16. self.name = name
  17. self.age  = age
  18. }
  19. }
  20. class Student: Person {
  21. var school: String
  22. init (name: String, age: Int, school: String) {       //指定构造函数
  23. self.school = school
  24. super.init(name: name, age: age)
  25. }
  26. convenience override init (name: String, age: Int) {//便利构造函数
  27. self.init(name: name, age: age, school: "清华大学")
  28. }
  29. }
  30. let student = Student()
  31. print("学生: \(student.description())")

构造函数之间的调用形成了构造函数链,如图所示。

Swift限制构造函数之间的代理调用的规则有3条,如下所示。

指定构造函数必须调用其直接父类的的指定构造函数。从图可见,Student中的④号指定构造函数调用Person中的③号指定构造函数。

    • 便利构造函数必须调用同一类中定义的其他构造函数。从图可见,Student中的⑤号便利构造函数调用同一类中的④号便利构造函数,Person中的①号便利构造函数调用同一类中的②号便利构造函数。

    • 便利构造函数必须最终以调用一个指定构造函数结束。从图可见,Student中的⑤号便利构造函数调用同一类中的④号指定构造函数,Person中的②号便利构造函数调用同一类中的③号指定构造函数。

  • ==================================================
  • Swift中的子类构造函数的来源有两种:自己编写和从父类继承。并不是父类的所有的构造函数都能继承下来,能够从父类继承下来的构造函数是有条件的,如下所示。

    • 条件1:如果子类没有定义任何指定构造函数,它将自动继承所有父类的指定构造函数。

    • 条件2:如果子类提供了所有父类指定构造函数的实现,无论是通过条件1继承过来的,还是通过自己编写实现的,它都将自动继承所有父类的便利构造函数。

    下面看示例代码:

    1. class Person {
    2. var name: String
    3. var age: Int
    4. func description() -> String {
    5. return "\(name) 年龄是: \(age)"
    6. }
    7. convenience init () {
    8. self.init(name: "Tony")
    9. self.age = 18
    10. }
    11. convenience init (name: String) {
    12. self.init(name: name, age: 18)
    13. }
    14. init (name: String, age: Int) {
    15. self.name = name
    16. self.age  = age
    17. }
    18. }
    19. class Student: Person {
    20. var school: String
    21. init (name: String, age: Int, school: String) {
    22. self.school = school
    23. super.init(name: name, age: age)
    24. }
    25. convenience override init (name: String, age: Int) {
    26. self.init(name: name, age: age, school: "清华大学")
    27. }
    28. }
    29. class Graduate: Student {
    30. var special: String = ""
    31. }

    来看看符合条件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—默认构造函数-备的更多相关文章

  1. 《从零开始学Swift》学习笔记(Day 37)——默认构造函数

    原创文章,欢迎转载.转载请注明:关东升的博客 结构体和类的实例在构造过程中会调用一种特殊的init方法,称为构造函数.构造函数没有返回值,可以重载.在多个构造函数重载的情况下,运行环境可以根据它的外部 ...

  2. C++的默认构造函数与构造函数

    今天看书,忽然发现自己对默认构造函数/构造函数的理解很模糊,在实际项目中写类时,这些细节问题并没有涉及到.因此,就专门对着<C++ Primer Plus>将默认构造函数/构造函数这一块简 ...

  3. C++ 合成默认构造函数的真相

    对于C++默认构造函数,我曾经有两点误解: 类如果没有定义任何的构造函数,那么编译器(一定会!)将为类定义一个合成的默认构造函数. 合成默认构造函数会初始化类中所有的数据成员. 第一个误解来自于我学习 ...

  4. C++中默认构造函数中数据成员的初始化

    构造函数的任务是初始化数据成员的,在类中,如果没有显示定义任何构造函数,编译器将为我们创建一个构造函数,称为合成的默认构造函数,合成的默认构造函数使用与变量初始化相同的规则来初始化成员.即当类中的数据 ...

  5. [C++]默认构造函数

    默认构造函数(default constructor)就是在没有显示提供初始化式时调用的构造函数.它由不带参数的构造函数,或者为所有的形参提供默认实参的构造函数定义.若个定义某个类的变量时没有提供初始 ...

  6. 【C++对象模型】构造函数语意学之一 默认构造函数

    默认构造函数,如果程序员没有为类定义构造函数,那么编译器会在[需要的时候]为类合成一个构造函数,而[需要的时候]分为程序员需要的时候和编译器需要的时候,程序员需要的时候应该由程序员来做工作,编译器需要 ...

  7. C++关于编译器合成的默认构造函数

    有两个常见的误解: 1.任何类如果没有定义默认构造函数,就会被合成出一个来. 2.编译器合成的默认构造函数会显式地设定类内每一个数据成员的默认值. 对于第一个误解,并不是任何类在没有显式定义默认构造函 ...

  8. C++默认构造函数的一点说明

    大多数C++书籍都说在我们没有自己定义构造函数的时候,编译器会自动生成默认构造函数.其实这句话我一直也是 深信不疑.但是最近看了一些资料让我有了一点新的认识. 其实我觉得大多数C++书籍之所以这样描述 ...

  9. C++结构体:默认构造函数,复制构造函数,重载=运算符

    C++结构体提供了比C结构体更多的功能,如默认构造函数,复制构造函数,运算符重载,这些功能使得结构体对象能够方便的传值. 比如,我定义一个简单的结构体,然后将其作为vector元素类型,要使用的话,就 ...

随机推荐

  1. Java学习日记 I/O

    File类1.String[] list() 返回一个目录下文件和文件夹路径的字符串数组2.File[] listFiles() 以File类对象数组,返回目录下的所有文件和文件夹3.isDirect ...

  2. Scala 编程(一)Scala 编程总览

    Scala 简介 Scala 属于“可伸展语言”,源于它可以随使用者的需求而改变和成长.Scala 可以应用在很大范围的编程任务上,小到脚本大到建立系统均可以. Scala 跑在标准 Java 平台上 ...

  3. des加密解密源码 C# key值问题

    公司协议安全需求.需要对传输内容做des.md5加密. 因为是新人.刚交给我这个任务的时候有点眩晕.就开始在网上找各种des加密的内容.因为不懂以为需要把原理也搞明白,最后误了时间.把自己也搞糊涂了. ...

  4. G - Arctic Network - poj2349

    在北极圈有一些基地,这些基地需要建立通讯网络,他们可以通过卫星直接通信或者无线通信,基地有S个卫星,N个基地,不过无线通信的传输距离是D,距离越远费用越高,现在想知道D最小是多少. 分析:使用krus ...

  5. 简单的多表插入(oracle)

    简单的多表插入语句: insert all into 表1(字段1,2...) values(值1,值2......) into 表2(字段1,2...)) values(值1,值2......) s ...

  6. Ensures there will be no 'console is undefined' errors

    很早之前项目中遇到过这种bug, 当时没有多留意,只是暂时把笔记留了下来,今天整理笔记的时候,看到了,故先整理在此,具体用法下次遇到再好好理解理解.如果有筒子遇到过,麻烦留言说一下,先谢谢啦. //E ...

  7. requirejs2读书笔记

    If you want to do require() calls in the HTML page, then it is best to not use data-main. data-main ...

  8. Java字符串的最大长度

    在cpp中为了可移植性,string的长度是string::size_type,突然就想知道java允许的最大字符串长度为多少.看String的源码: public final class Strin ...

  9. 解决git提交问题error: The requested URL returned error: 403 Forbidden while accessing

    git提交代码时,出现这个错误"error: The requested URL returned error: 403 Forbidden while accessing https&qu ...

  10. 重叠I/O之事件通知

      在 Winsock 中,重叠 I/O(Overlapped I/O)模型能达到更佳的系统性能,高于select模型.异步选择和事件选择三种.重叠模型的基本设计原理便是让应用程序使 用一个重叠的数据 ...