Einführung in virtuelle Methoden
Teil des Abschnitts Objektorientierte Programmierung der GDScript-Journey von Coddy. Lektion 31 von 65.
Python hat magische Methoden wie __init__ und __str__, die von der Sprache für dich aufgerufen werden. In Godot gibt es dafür die virtuelle Methode: eine Methode mit einem festen Namen, der mit einem Unterstrich beginnt und die du in deiner Klasse definierst. Godot ruft sie zum richtigen Zeitpunkt auf. Du hast bereits zwei verwendet:
_init()wird ausgeführt, wennnew()das Objekt erstellt, und erhält die annew()übergebenen Argumente._ready()wird ausgeführt, wenn ein Node in den Szenenbaum eintritt. Dort beginntmain.gd.
Andere sind _to_string(), das aufgerufen wird, wenn ein Objekt ausgegeben wird, die Iteratormethoden, mit denen eine for-Schleife ein Objekt durchlaufen kann (beides in den nächsten Lektionen), und _notification(), das Ereignisse von der Engine empfängt. Eines davon, NOTIFICATION_PREDELETE, tritt unmittelbar vor dem Löschen des Objekts ein:
# torch.gd
class_name Torch
extends RefCounted
var label: String
func _init(new_label: String = "Torch") -> void:
label = new_label
print(label, " lit")
func _notification(what: int) -> void:
if what == NOTIFICATION_PREDELETE:
print(label, " burned out")# main.gd
var torch := Torch.new("Hall torch") # Flurfackel angezündet
torch = null # Flurfackel ausgebranntEin RefCounted-Objekt wird gelöscht, sobald keine Variable mehr darauf verweist. Daher sendet torch = null die Benachrichtigung sofort. Der Standardwert in _init() macht das Argument von new() optional: Torch.new() erstellt eine Fackel namens Torch.
Python verwendet ebenfalls magische Methoden für Operatoren, wie __add__ für + und __eq__ für ==. GDScript unterstützt keine Operatorüberladung: potion_a + potion_b ist ein Fehler. Schreibe stattdessen eine Methode:
# potion.gd
class_name Potion
extends RefCounted
var power: int
func _init(start_power: int) -> void:
power = start_power
func combined(other: Potion) -> Potion:
return Potion.new(power + other.power)potion_a.combined(potion_b) gibt einen neuen Trank zurück und lässt beide ursprünglichen unverändert. == zwischen zwei Objekten prüft, ob beide Seiten dasselbe Objekt sind, nicht ob ihre Werte übereinstimmen: Potion.new(5) == Potion.new(5) ist false. Schreibe eine Methode wie equals(other), wenn du Werte vergleichen musst.
Aufgabe
EinfachSchreibe die Klasse Counter in counter.gd:
_init(start = 0, step_size = 1)speichert den Startwert invalueund die Schrittweite instep. Die Standardwerte stehen bereits in der Signatur, daher funktionierenCounter.new(),Counter.new(5)undCounter.new(5, 2).tick()addiertstepzuvalue.plus(other)ersetzt den+-Operator, dessen Definition GDScript nicht zulässt: Die Methode gibt einen neuenCounterzurück, dessen Wert die Summe beider Werte und dessen Schrittweite die Schrittweite dieses Zählers ist. Keiner der beiden Zähler wird verändert.equals(other)gibttruezurück, wenn beide Zähler denselben Wert haben.
Der bereitgestellte Code liest zwei Zeilen ein, die die Zähler a und b erstellen (eine leere Zeile, START oder START STEP), gefolgt von einer Zeile mit der Anzahl der Ticks für a und b. Er gibt beide Zähler, ihre Summe, die Gleichheit ihrer Werte und die Information aus, ob a == b gilt. Für die Zeilen 5, 2 3 und 3 1 gibt er Folgendes aus:
a: 8 (step 1)
b: 5 (step 3)
a plus b: 13 (step 1)
same value: false
same object: falseDein Code gehört in counter.gd. main.gd enthält den bereitgestellten Eingabe-/Ausgabecode und kann nicht bearbeitet werden.
Probier es selbst
extends Node
func _ready():
# Vorgegebener Ein-/Ausgabecode: unverändert lassen
var a := make_counter(OS.read_string_from_stdin())
var b := make_counter(OS.read_string_from_stdin())
var ticks := OS.read_string_from_stdin().split(" ")
for i in int(ticks[0]):
a.tick()
for i in int(ticks[1]):
b.tick()
print("a: %d (step %d)" % [a.value, a.step])
print("b: %d (step %d)" % [b.value, b.step])
var total := a.plus(b)
print("a plus b: %d (step %d)" % [total.value, total.step])
print("same value: %s" % a.equals(b))
print("same object: %s" % (a == b))
func make_counter(line: String) -> Counter:
var parts := line.split(" ", false)
if parts.is_empty():
return Counter.new()
if parts.size() == 1:
return Counter.new(int(parts[0]))
return Counter.new(int(parts[0]), int(parts[1]))
Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Objektorientierte Programmierung
1Grundlagen der OOP
Externe DateienEinführung in die OOPKlassen vs. ObjekteDas Schlüsselwort selfMethodenEigenschaftenKonstruktor (_init)Wiederholung – Einfacher Taschenrechner4Polymorphie
Methodenüberschreibung erneut betrachtetDuck-TypisierungAbstrakte Klassen und MethodenSchnittstellendesignRückblick – Formrechner2Klassenattribute
Instanz- vs. statische VariablenStatische FunktionenProperty-SetterProperty-GetterPrivat nach KonventionWiederholung – Bankkontenverwaltung5Kapselung
Öffentliche und private MemberValidierung mit SetternInformationsverbergenSchreibgeschützte EigenschaftenRückblick – System zur Schülerverwaltung8Fortgeschrittene OOP-Konzepte
Komposition vs. VererbungInnere KlassenNodes als KomponentenRefCounted vs. NodeEnums in Klassen11Projekt: Bibliotheksverwaltung
ProjektübersichtBuch- und Benutzerklassen3Vererbung
Grundlegende VererbungDas Schlüsselwort superMethodenüberschreibungVererbungskettenTypprüfungen mit isWiederholung – Mitarbeiterhierarchie6Spezielle Methoden
Einführung in virtuelle MethodenDie _to_string-MethodeBenutzerdefinierte IteratorenRückblick – Benutzerdefinierte Liste9Entwurfsmuster Teil 1
Einführung in EntwurfsmusterSingleton-MusterFactory-MusterBeobachter-MusterStrategie-Muster12Abschließende Herausforderungen
E-Learning-PlattformBankensystemEntwicklung von SpielfigurenFahrzeugvermietungÜbe selbstständig: Online-GDScript-Compiler