Swift—默认构造函数-备

结构体和类的实例在构造过程中会调用一种特殊的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类实现了父类指定构造函数,因此也继承了父类的另外两个便利构造函数。

时间: 2024-10-12 20:37:05

Swift—默认构造函数-备的相关文章

Swift 2.0学习笔记(Day 37)——默认构造函数

Swift 2.0学习笔记(Day 37)--默认构造函数原创文章,欢迎转载.转载请注明:关东升的博客 结构体和类的实例在构造过程中会调用一种特殊的init方法,称为构造函数.构造函数没有返回值,可以重载.在多个构造函数重载的情况下,运行环境可以根据它的外部参数名或参数列表调用合适的构造函数.默认构造函数结构体和类在构造过程中会调用一个构造函数,即便是没有编写任何构造函数,编译器也会提供一个默认的构造函数.下面看示例代码: class Rectangle { var width: Double

没有默认构造函数,如何定义对象的数组

假设一个定义类的默认构造函数,然后构造这个类的对象数组将是一个问题.从而实现遗嘱new运营商掰开使用代码. 首先,分配内存,然后调用构造函数对象分配内存.的代码做一个简单的备忘. //未定义构造函数的类不能定义该类的对象数组,内置类型除外 //operator new + ctor //dtor + operator delete //operator new[] + ctor //dtor + operator delete [] #include <bits/stdc++.h> using

没有默认构造函数,如何定义对象数组

如果一个类没有定义默认构造函数,那么构造该类的对象数组将会是一个问题.于是实现了一个将new操作符掰开了来用的代码.首先分配内存,然后再在分配的内存上调用构造函数构造对象,下面的代码做一个简单的备忘. //没有定义构造函数的类不能定义该类的对象数组,内置类型除外 //operator new + ctor //dtor + operator delete //operator new[] + ctor //dtor + operator delete [] #include <bits/stdc

【C/C++】构造函数、默认构造函数、成员初始化列表

常见问题 Q1. 下列关于构造函数的描述中,错误的是( ) A. 构造函数可以设置默认的参数 B. 构造函数在定义类对象时自动执行 C. 构造函数可以是内联函数 D. 构造函数不可以重载 Q2. 下列代码中a.b的各个成员变量值是多少? 1 class Student 2 { 3 public: 4 Student() {} 5 void show(); 6 private: 7 string name; 8 int number; 9 int score; 10 }; 11 Student a

编译器生成默认构造函数的情况

在类没有显示声明构造函数的情况下,编译器并不总是为我们自动生成默认构造函数,以下4种情况,编译器才会为我们自动生成默认构造函数: 1.类中有一个类成员含有默认构造函数的,编译器会为该类自动生成默认构造函数,自动插入代码,调用该成员的构造函数: 2.基类中含有默认构造函数,编译器会为该类自动生成默认构造函数,自动插入代码,调用基类的构造函数: 3.类中含有虚函数时,由于编译器要为该类生成虚函数表vtable,并为该类的对象生成指向该vtable的vptr,所以需要为该类合成默认构造函数: 4.虚继

Unity3D的IL2CPP平台找不到默认构造函数的坑

最初发现这个问题的情况是,当游戏用IL2CPP平台发布IOS版本的时候,会遇到某些dll格式的插件会导致游戏抛异常崩溃,比如FullInspector和Behavior Designer.所抛的异常是找不到某些类的默认构造函数. 后来发现,不只是某些插件会报这种异常,很多json格式的序列化功能也会在IL2CPP平台上抛找不到默认构造函数的异常. 导致这个问题的原因是,IL2CPP版本在AOT编译时的一些优化机制导致的.想要详细了解这个机制的话可以看文档:http://docs.unity3d.

C++构造函数语意学——默认构造函数

概述 在 class 中,若程序员没有为该 class object 定义 default constructors,则编译器会根据需要产生一个 implicit default constructor,该 implicit default constructor 被认为是 trivial(无用的).那编译器怎样才能产生一个 nontrivial implicit default constructor?以下四个方面会产生nontrivial implicit default construct

C++默认构造函数的问题

C++ defaul construct :缺省构造函数(默认构造函数) 定义:第一种   构造函数没有参数,即是 A()形式的 第二种   构造函数的全部参数由缺省值提供,A(int a=0,int b=0) 编译器添加的默认构造函数的条件:   如果创建一个类你没有写任何构造函数,则系统会自动生成默认的无参构造函数,函数为空,什么都不做(这只是一种情况而言,此构造函数是trival 派生类和基类的关系: 我们通常说的派生类和基类,我们调用派生类的自定义的构造函数的时候,派生类会自动调用基类中

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

对于C++默认构造函数,我曾经有两点误解: 类如果没有定义任何的构造函数,那么编译器(一定会!)将为类定义一个合成的默认构造函数. 合成默认构造函数会初始化类中所有的数据成员. 第一个误解来自于我学习C++的第一本书 <C++ Primer>,在书中392页:“只有当一个类没有定义构造函数时,编译器才会自动生成一个默认构造函数”. 实际上这句话也没有说错,它说明了默认构造函数定义的必要非充分条件,然而却给当时初学C++的我造成了一定的误解. 第二个误解依旧来自于Primer中的一句话:“合成的