抽象クラスと抽象メソッド
CoddyのGDScriptジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 23/65。
拡張することだけを目的とするクラスもあります。どの図形にも面積がありますが、その図形が円なのか長方形なのかがわかるまでは、面積を計算できません。そのようなクラスには、class_nameの上の行に@abstractを付けます。
# 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子クラスがそのうちの1つを実装し忘れると、Godotは実行前に次のように報告します:Class "Square" must implement "Shape.perimeter()" and other inherited abstract methods or be marked as "@abstract"。そのため、作成できるすべてのオブジェクトにはarea()とperimeter()があります。
抽象クラスにも変数や_init()を持たせることができます。子クラスは通常どおりsuper()を使って呼び出します。
チャレンジ
簡単ある店舗では2種類の支払い方法を受け付けています。各支払いには金額と領収書がありますが、手数料と名前は支払い方法によって異なります。
PaymentMethodを抽象クラスにし、2つの抽象メソッドfee() -> floatとmethod_name() -> Stringを宣言してください。receipt()を作成し、各数値を小数点以下2桁で表示したNAME: paid AMOUNT, fee FEE, total TOTALを返してください(合計は金額と手数料を足した値です)。CreditCard:手数料は金額の3%(amount * 0.03)で、名前はCredit cardです。BankTransfer:手数料は1.5です。ただし、金額が100以上の場合は0.0で、名前はBank transferです。
子クラスはPaymentMethodのコンストラクターを使用します。用意されているコードは、支払い件数を読み込んだ後、支払いごとに1行を読み込みます。形式は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オンラインコンパイラ