Menu
CoddyTech

Classi e metodi astratti

Fa parte della sezione Programmazione orientata agli oggetti del percorso GDScript di Coddy. Lezione 23 di 65.

Alcune classi esistono solo per essere estese. Ogni forma ha un'area, ma non puoi calcolarla finché non sai se la forma è un cerchio o un rettangolo. Contrassegna una classe del genere con @abstract, sulla riga sopra 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()]

Una @abstract func ha una firma e non ha un corpo: nessun due punti e nessun codice dopo. Indica che ogni classe figlia deve fornire questo metodo. describe() è un metodo normale; le classi figlie lo ereditano e può già chiamare i metodi astratti.

Non puoi creare un oggetto di una classe astratta. Shape.new() interrompe il programma prima che inizi con Parse Error: Cannot construct abstract class "Shape".

Una classe derivata che implementa ogni metodo astratto è una classe normale:

# 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

Se una classe figlia ne omette una, Godot lo segnala prima dell'esecuzione: Class "Square" must implement "Shape.perimeter()" and other inherited abstract methods or be marked as "@abstract". Quindi ogni oggetto che puoi creare ha area() e perimeter().

Una classe astratta può comunque avere variabili e un _init(). Le classi figlie la chiamano con super() come al solito.

challenge icon

Sfida

Facile

Un negozio accetta due metodi di pagamento. Ogni pagamento ha un importo e una ricevuta, ma la commissione e il nome dipendono dal metodo.

  • Rendi PaymentMethod astratta e dichiara due metodi astratti: fee() -> float e method_name() -> String. Scrivi receipt(), che restituisce NAME: paid AMOUNT, fee FEE, total TOTAL con due cifre decimali per ogni numero (il totale è l'importo più la commissione).
  • CreditCard: la commissione è il 3% dell'importo (amount * 0.03) e il nome è Credit card.
  • BankTransfer: la commissione è 1.5, oppure 0.0 quando l'importo è pari o superiore a 100, e il nome è Bank transfer.

Le classi figlie usano il costruttore di PaymentMethod. Il codice fornito legge quanti pagamenti seguono, poi una riga per ogni pagamento: card AMOUNT oppure transfer AMOUNT. Stampa ogni ricevuta e la somma delle commissioni. Per card 50 e transfer 120 stampa:

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

Il tuo codice va inserito in payment_method.gd, credit_card.gd e bank_transfer.gd. main.gd contiene il codice fornito per l'input/output e non può essere modificato.

Provalo tu

extends Node

func _ready():
	# Codice di input/output fornito: lascialo così com'è
	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)
quiz iconMettiti alla prova

Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.

Tutte le lezioni di Programmazione orientata agli oggetti

Esercitati da solo: Compilatore GDScript online