再谈方法重写
本课属于 Coddy GDScript 学习旅程的“面向对象编程”单元。第 21 课,共 65 课。
多态的意思是“多种形式”:一次方法调用会根据接收调用的对象所属的类执行不同的操作。重写让这一切成为可能。
# animal.gd
class_name Animal
extends RefCounted
func speak() -> String:
return "..."# dog.gd
class_name Dog
extends Animal
func speak() -> String:
return "Woof!"# cat.gd
class_name Cat
extends Animal
func speak() -> String:
return "Meow!"Array[Animal] 可以保存它们所有对象。循环调用 speak(),而无需知道每个元素属于哪个类,每个对象都会用自己的版本作出响应:
var animals: Array[Animal] = [Dog.new(), Cat.new(), Animal.new()]
for animal in animals:
print(animal.speak())Woof!
Meow!
...带有 Animal 参数的函数也是如此。它可以接受所有子类,包括你以后添加的类,无需做任何修改:
func make_it_speak(animal: Animal) -> void:
print("It says ", animal.speak())make_it_speak(Cat.new())It says Meow!把它和逐个检查类进行比较。每增加一个新类,if animal is Dog: 分支链就必须变长。使用重写时,每个类都带有自己的行为,而调用它的代码保持不变。
挑战
简单车库通过一个 Array[Vehicle] 处理所有车辆。在 vehicle.gd 中,wheels() 返回 0,sound() 返回 ...。
- 在
Vehicle中编写describe()。它会调用wheels()和sound(),并返回BRAND: N wheels, SOUND。 Car重写wheels(),使其返回4,并重写sound(),使其返回Vroom。Motorcycle重写这两个方法,分别使其返回2和Brrm。Truck已经存储了trailers的数量。它重写wheels(),使其返回6加上每个拖车4个轮子,并重写sound(),使其返回Honk。
子类不会重写 describe()。提供的代码会读取后续车辆的数量,然后每辆车读取一行:car BRAND、motorcycle BRAND、truck BRAND TRAILERS 或 vehicle BRAND。代码会打印每辆车的 describe() 结果,以及 wheels() 的总和。输入 car Toyota 和 truck Volvo 2 时,会打印:
Toyota: 4 wheels, Vroom
Volvo: 14 wheels, Honk
Total wheels: 18你的代码要写在 vehicle.gd、car.gd、motorcycle.gd 和 truck.gd 中。main.gd 中包含提供的输入和输出代码,不能编辑。
亲手试试
extends Node
func _ready():
# 提供的输入输出代码:保持原样
var count := int(OS.read_string_from_stdin())
var vehicles: Array[Vehicle] = []
for i in count:
var p := OS.read_string_from_stdin().split(" ")
if p[0] == "car":
vehicles.append(Car.new(p[1]))
elif p[0] == "motorcycle":
vehicles.append(Motorcycle.new(p[1]))
elif p[0] == "truck":
vehicles.append(Truck.new(p[1], int(p[2])))
else:
vehicles.append(Vehicle.new(p[1]))
var total := 0
for v in vehicles:
print(v.describe())
total += v.wheels()
print("Total wheels: %d" % total)
这节课包含一个小测验。开始学习即可作答,并记录你的进度。
面向对象编程中的所有课
自己练习: GDScript 在线编译器