【问题标题】:When override function with default value parameter, how to keep the default value same as superclass?使用默认值参数覆盖函数时,如何保持默认值与超类相同?
【发布时间】:2016-12-13 07:23:54
【问题描述】:

例如,这是一个超类:

class A {
    public init(a: String = "aaaa") {
        // this class is in a framework, and the subclass use that framework.
        ......
    }
}

有没有办法编写一个子类并用参数a的相同默认值覆盖init

超类在框架内。一个项目使用这个框架,想用默认参数值覆盖一个函数,但是在覆盖函数中似乎没有办法获取超类的默认参数值。我可以在子类中编写另一个函数,例如检查参数是否为 nil,然后使用其默认值调用超类,否则,将子类参数值传递给超类。但是我想找到一种方法来编写完全相同的函数名,即覆盖超类函数。

【问题讨论】:

  • 本来要编辑我的评论,却误删了……不管怎样,有没有办法在运行时捕获超类的默认参数值?例如。如果您知道上面初始化程序中的a 被分配给某个类属性(例如,aa)。在这种情况下,您可以将a 的默认值捕获为类的某个静态属性(对于此示例,static let defaultValue = A().aa,假设aa 是可访问的),并使用此属性作为默认值上面初始化器的override(例如override init(a: String = Foo.defaultValue) { ... })。

标签: swift function inheritance overriding default-value


【解决方案1】:

(这个答案是最新的 Swift 3)

将默认参数值放置在 convenience 初始化器中,覆盖该便捷初始化器指向的 designated 初始化器

您可以让带有默认参数的公共超类初始化程序为convenience 初始化程序,该初始化程序将用作超类和子类的初始化程序“接口”。这个便利的初始化器又简单地调用 fileprivatedesignated 初始化器,它是您在子类中覆盖的初始化器。例如

public class A {
    let a: String

    /* public initializer */
    public convenience init(a: String = "aaaa") {
        self.init(b: a)
    }
    
    /* "back-end" fileprivate initializer: implement initializer
       logic here, and override this initializer in subclasses */
    fileprivate init(b: String) {
        self.a = b
        print("super:", b)
    }
}

public class B: A {
    let b: String
    
    override fileprivate init(b: String) {
        self.b = "sub_" + b
        print("sub:", b)
      
        super.init(b: b)
    }
}

/* The following initializations all call the convenience initializer defined in A */
let a = A()         // prints> super: aaaa
let b = B()         // prints> sub: aaaa, super: aaaa
let c = B(a: "foo") // prints> sub: foo, super: foo

print(a.a) // aaaa
print(b.a) // aaaa
print(b.b) // sub_aaaa
print(c.a) // foo
print(c.b) // sub_foo

在这个简单的例子中,子类覆盖了它的父类的所有指定初始化器(这里:一个指定的初始化器),这就是为什么它的超类的所有便利初始化器(这里:一个)都可用(由子类继承),如Language Guide - Initialization - Class Inheritance and Initialization - Automatic Initializer Inheritance 中的规则 2 所述。

规则 1

如果你的子类没有定义任何指定的初始化器,它 自动继承其所有超类指定的初始化器。

规则 2

如果您的子类提供了其超类的 all 的实现 指定的初始化器——要么按照规则 1 继承它们,要么通过 提供自定义实现作为其定义的一部分——然后它 自动继承所有超类的便利构造器。

【讨论】:

  • 如果那是一个私有初始化器,我什至不知道它时如何覆盖它。我想在另一个文件中写子类。
  • @zgjie 我假设您,作为开发人员,知道应用程序类在层次级别上的实现,因为您的问题与这件事有关。您从未在问题中提到过这一点,但是如果子类未在与 superc 相同的源文件中定义。 (即,超出私有可见范围),您可以让上面的私有初始化程序是内部的(假设两个不同的源文件在同一个定义模块中):许多 stdlib 实现诉诸非私有访问方法,应该由于访问控制中的这些限制,因此必须是私有的。
  • 实际上,我想假设超类位于封闭源代码框架内。一个项目使用这个框架,想用默认参数值覆盖一个函数,但是在覆盖函数中似乎没有办法获取超类的默认参数值。我可以在子类中编写另一个函数,例如检查参数是否为nil,然后使用其默认值调用超类,否则,将子类参数值传递给超类。但是我想找到一种方法来编写完全相同的函数名,即覆盖超类函数。
  • @zgjie 考虑将这些详细信息添加到您的问题中,并将其用作您提出的下一个问题的反馈(即,如果您对您的问题有特定限制,请描述它们!)。
  • 这很好用,但是如果我保留 A 类中 init(b: String) 定义的“私有”指令,则 B 类中的定义失败,说参数错误,意味着 B 类看不到 A 表单,Swift 规范有什么变化吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-20
相关资源
最近更新 更多