抽象类和方法
本课属于 Coddy GDScript 学习旅程的“面向对象编程”单元。第 23 课,共 65 课。
有些类的存在只是为了被扩展。每种形状都有面积,但只有知道形状是圆形还是矩形后,才能计算面积。将这类类标记为 @abstract,并写在 class_name 上方一行:
# shape.gd
@abstract
class_name Shape
extends RefCounted
@abstract func area() -> float
@abstract func perimeter() -> float
func describe() -> String:
return "Area %.1f, perimeter %.1f" % [area(), perimeter()]@abstract func 有签名但没有函数体:没有冒号,后面也没有代码。它表示每个子类都必须提供这个方法。describe() 是一个普通方法,子类会继承它,而且它可以直接调用抽象方法。
你不能创建抽象类的对象。Shape.new() 会在程序开始前停止运行,并显示 Parse Error: Cannot construct abstract class "Shape".
实现了所有抽象方法的子类是一个普通类:
# rectangle.gd
class_name Rectangle
extends Shape
var width: float
var height: float
func _init(w: float, h: float) -> void:
width = w
height = h
func area() -> float:
return width * height
func perimeter() -> float:
return 2 * (width + height)var rect := Rectangle.new(4.0, 6.0)
print(rect.describe())Area 24.0, perimeter 20.0如果子类漏掉了其中一个,Godot 会在运行前报告错误:Class "Square" must implement "Shape.perimeter()" and other inherited abstract methods or be marked as "@abstract"。因此,你创建的每个对象都有 area() 和 perimeter()。
抽象类仍然可以有变量和 _init()。子类仍像往常一样用 super() 调用它。
挑战
简单一家商店接受两种付款方式。每笔付款都有金额和收据,但手续费和名称取决于付款方式。
- 将
PaymentMethod设为抽象类,并声明两个抽象方法:fee() -> float和method_name() -> String。编写receipt(),使其返回NAME: paid AMOUNT, fee FEE, total TOTAL,每个数字都保留两位小数(总金额为金额加手续费)。 CreditCard:手续费为金额的 3%(amount * 0.03),名称为Credit card。BankTransfer:手续费为1.5;金额大于或等于100时,手续费为0.0,名称为Bank transfer。
子类使用 PaymentMethod 的构造函数。提供的代码会读取后续付款的数量,然后为每笔付款读取一行:card AMOUNT 或 transfer AMOUNT。它会输出每张收据以及手续费总和。对于 card 50 和 transfer 120,输出为:
Credit card: paid 50.00, fee 1.50, total 51.50
Bank transfer: paid 120.00, fee 0.00, total 120.00
Total fees: 1.50你的代码应写在 payment_method.gd、credit_card.gd 和 bank_transfer.gd 中。main.gd 存放了提供的输入/输出代码,不能修改。
亲手试试
extends Node
func _ready():
# 提供的输入输出代码:保持原样
var count := int(OS.read_string_from_stdin())
var total_fees := 0.0
for i in count:
var p := OS.read_string_from_stdin().split(" ")
var payment: PaymentMethod
if p[0] == "card":
payment = CreditCard.new(float(p[1]))
else:
payment = BankTransfer.new(float(p[1]))
print(payment.receipt())
total_fees += payment.fee()
print("Total fees: %.2f" % total_fees)
这节课包含一个小测验。开始学习即可作答,并记录你的进度。
面向对象编程中的所有课
自己练习: GDScript 在线编译器