您是否需要从每个子类的函数中调用超类的实现?

时间:2019-04-01 00:30:44

标签: swift functional-programming subclass superclass

例如您定义了一个子类,该子类将覆盖其父类中的函数f。在覆盖内部,您需要调用超类的f函数。

3 个答案:

答案 0 :(得分:1)

答案是错误的,通常不需要在Swift或OOP中调用要重写的超类方法。如果这样做的话,那将是一个可怕的局限!有时您实际上不应该调用它,也许最常见的例子是您以编程方式创建UIViewController并必须重写loadView() 而无需调用{{1} }。

答案 1 :(得分:1)

这个问题的答案实际上与Swift无关,但与所有OOP语言都有关。

简单的答案是:不,您不是不需要来调用超类实现。

在文档中应说明是否应调用超类实现。如果不确定,通常应始终调用超级实现。

您必须考虑以下事实:超类在方法内部做了某些事情,如果您不调用超类实现,则子类不必正常工作。

不调用超类实现意味着您要阻止超类实现发生,这通常意味着您的整个继承模型都存在缺陷。

一个值得注意的例外是超类提供了一些您要在子类内部替换的默认实现的情况(例如UIViewController.loadView)。不过,这不是一个很常见的用例。

还有其他明显的例外,例如吸气剂。当您覆盖获取器以返回自定义对象时,通常无需调用super。但是,再次,即使是吸气剂也可以从技术上初始化超类中的某些结构,并且可能需要调用超类。

答案 2 :(得分:1)

默认情况是您调用super除非,除非您知道自己没有破坏该功能。


我已经创建了gist。您可以将其复制到自己的游乐场并玩耍。但是答案是:

我对您的困惑很深。您基本上是在问扩展行为与覆盖行为之间有什么区别。

Swift不能很好地告诉您它们之间的区别。 他们俩的共同点是都需要用override标记该函数,但是有时候您除了做超类的实现(扩展)之外还要做其他事情,有时候您只是完全重写了它(覆盖)

假设我们有以下课程:

class Person {

    var age : Int?

    func incrementAge() {
        guard age != nil else {
            age = 1
            return
        }
        age! += 1
    }

    func eat() {
        print("eat popcorn")
    }
}

我们只需对其进行初始化即可:

var p1 = Person()
p1.incrementAge() // works fine

现在假设我们这样做了:

class Boy : Person{

    override func incrementAge() {
        age! += 2
    }
}

var b1 = Boy()
b1.incrementAge()

您认为会发生什么?!

它将崩溃。因为在超类中,我们正在对nil进行age检查,但是在我们的子类中,我们从不调用super

要使其正常工作,我们必须致电super

class GoodBoy : Person{

    override func incrementAge() {
        super.incrementAge()
        age! += 2
    }
}

var b2 = GoodBoy()
b2.incrementAge() // works fine. 

我们可以在不直接致电super的情况下逃脱。

class AlternateGoodBoy : Person{

    override func incrementAge() {
        guard age != nil else {
            age = 1
            return
        }
        age! += 2
    }
}

var b3 = AlternateGoodBoy()
b3.incrementAge() // works fine.

^^上面的方法有效,但是我们并不总是知道超类的实现。一个真实的例子是UIKit。我们不知道调用viewDidLoad时会发生什么。因此,我们必须致电super.viewDidLoad


话虽这么说,有时我们不能只叫super而就好了,因为我们知道super在做什么,或者根本不在乎,并且想要完全摆脱它。例如:

class Girl : Person{
    override func eat() {
        print("eat hotdog")
    }
}

var g1 = Girl()
g1.eat() // doesn't crash, even though you overrode the behavior. It doesn't crash because the call to super ISN'T critical

最常见的情况是您调用super,但还要在其上添加一些内容。

class Dad : Person {
    var moneyInBank = 0
    override func incrementAge() {
        super.incrementAge()
        addMoneyToRetirementFunds()
    }

    func addMoneyToRetirementFunds() {
        moneyInBank += 2000
    }
}

var d1 = Dad()
d1.incrementAge()
print(d1.moneyInBank) // 2000