我正在学习关于swift,OOP和POP的所有知识,我试图找出swift如何在类之间传递重写的方法调用。我似乎无法找到具体的信息。 Swift编程语言手册有一个非常简短的Overriding Methods部分。我的问题最好在代码中描述:
class Life {
func test() { print("test called from Life class") }
func skippedTest() { print("skippedTest called from Life class") }
}
class Animal: Life {
override func test() { print("test called from Animal class") }
}
class Dog: Animal {
override func test() { print("test called from Dog class") }
override func skippedTest() { print("skippedTest called from Dog class") }
}
class Shitzu: Dog {
override func test() { print("test called from Shitzu class") }
}
let life = Life()
let animal = Animal()
let dog = Dog()
let shitzu = Shitzu()
print("--------------1---------------")
life.test()
animal.test()
dog.test()
shitzu.test()
print("--------------2---------------")
let array:[Life] = [life,animal,dog,shitzu]
for item in array { item.test() }
print("--------------3---------------")
life.skippedTest()
animal.skippedTest()
dog.skippedTest()
shitzu.skippedTest()
print("--------------4---------------")
for item in array { item.skippedTest() }
print("--------------5---------------")
let shitzuAsLife:Life = Shitzu()
(shitzuAsLife as! Life).test()
这是输出:
--------------1---------------
test called from Life class
test called from Animal class
test called from Dog class
test called from Shitzu class
--------------2---------------
test called from Life class
test called from Animal class
test called from Dog class
test called from Shitzu class
--------------3---------------
skippedTest called from Life class
skippedTest called from Life class
skippedTest called from Dog class
skippedTest called from Dog class
--------------4---------------
skippedTest called from Life class
skippedTest called from Life class
skippedTest called from Dog class
skippedTest called from Dog class
--------------5---------------
test called from Shitzu class
我的结论是,无论你如何在类层次结构中强制转换类实例,它总是调用该方法的最专业版本。出于某种原因,这不是我所期望的。我希望当你在一个类化的类上调用一个方法时,你可以从你所转换的类中调用该方法。我有三个问题:
如果这个问题是重复的,或者我在RTFM时错过的RTFM答案,那么我将删除它。请指点我正确的方向。
答案 0 :(得分:1)
我做错了吗?
都能跟得上!
如果没有,这是swift的预期行为吗?
是的,这称为polymorphism.
如果是这样,那么你究竟如何调用重写方法的父类实现?
你不能,而你也不应该。
考虑这个例子:
class Human {
func eat() {
print("I just ate a well rounded meal of veggies, meat, potatoes and of course, desert.")
}
}
class Vegetarian: Human {
override func eat() {
print("I just ate a meal of veggies, tofu, and desert. No meat!")
}
}
如果此操作符合您的预期,则此代码为:
let human = Vegetarian() as Human
human.eat()
......会让素食者吃肉。他们当然不会对此感到高兴。
在许多情况下,子类需要与特殊消息(方法调用)不同的实现(方法),而不是超类提供的实现。在这种情况下,为类的消费者提供调用超类方法的能力可能导致对象进入不一致状态,因为您违反了它应该在其下工作的设计。
事实上,您的第二次测试证明了多态性的主要用例之一。你不会在这里产生相当大的影响,因为test()
并不重要。考虑这些动物类代表可以在屏幕上绘制的实体。绘制猫的程序与绘制狗非常不同。如果我有一个有多只猫,狗,马和蜂蜜獾的场景怎么办?需要[Cat]
,[Dog]
,[Horse]
和[HoneyBadger]
并分别迭代所有这些内容以在每个.draw()
上调用[Animal]
,这将非常不方便。相反,多态允许我存储Animal
数组,这是我想要绘制的所有动物的常见超类。 draw()
定义了Cat
方法并没有做太多事情,但事实证明它可以保证我可以对任何动物进行抽奖。我的Dog
,Animal
等都覆盖了draw()
的{{1}}定义,并提供了自己的实现。当我遍历我的阵列并告诉我所有的动物画自己时,他们按照自己的draw()
定义。
在前面的例子中,多态性带来了便利。这是一个展示您无法实现的功能的示例。考虑我的用户可以点击动物,然后拖动它们。让我知道哪些动物在拖动时移动,我需要知道选择了哪种动物。我会通过拥有我的场景的成员变量来做到这一点,定义为let selectedAnimal: Animal?
。每次我的用户点击动物时,我都会将selectedAnimal
设置为正确的动物实例。每当他们取消选择时,我都会将selectedAnimal
设置回nil
。拖动后,我可以拨打selectedAnimal?.moveTo(mouseX, mouseY)
。 moveTo
调用可能会因Horse
(疾驰),Dog
(在所有4上运行)和Cat
(它们都是懒惰的)而定义不同。如果没有多态性,我将无法存储未知(在编译时)具体时间的变量。多态性允许我将我的动物存储为Animal
,知道我发送的任何消息(我调用的方法)都将由最合适的覆盖执行。