PBXB64 OOP & Klassen
OOP & Klassen
Standard
Vollständige objektorientierte Programmierung with CLASS, INTERFACE, METHOD, PROPERTY, EVENTS FROM, EVENTS END, RAISEEVENT, IMPLEMENTS, and WITH. Multi-Subscriber-Event-Dispatch, Interface-Vererbung, and Property-Accessoren. Alles unterstützt von echtem Vtable- und Event-Helper-Runtime-Code.
CLASS with METHOD and PROPERTY
Klassen-Definition und -Verwendung
#COMPILE EXE
#DIM ALL
CLASS MyClass
INSTANCE count AS LONG
CLASS METHOD Create() ' constructor, runs when the object is created
count = 0
END METHOD
INTERFACE IMyClass
INHERIT IUNKNOWN
METHOD Increment() AS LONG
count = count + 1
METHOD = count
END METHOD
PROPERTY GET Counter() AS LONG
PROPERTY = count
END PROPERTY
END INTERFACE
END CLASS
FUNCTION PBMAIN() AS LONG
LOCAL obj AS IMyClass
LET obj = CLASS "MyClass"
obj.Increment()
obj.Increment()
PRINT "Count: "; obj.Counter ' 2
FUNCTION = 0
END FUNCTION
CLASS definiert einen Typ mit INSTANCE-Variablen und einem INTERFACE, das die METHOD- und PROPERTY-Member enthält. Objekte werden mit LET obj = CLASS "name" erzeugt; CLASS METHOD Create() dient als Konstruktor. Member werden per Punktnotation aufgerufen (Methoden mit oder ohne Klammern), mit echtem Vtable-Dispatch.
EVENTS FROM / EVENTS END / RAISEEVENT
Multi-Subscriber-Events
#COMPILE EXE
#DIM ALL
INTERFACE IEvents ' event interface: the shared contract
INHERIT IUNKNOWN
METHOD MyEvent(BYVAL iValue AS LONG)
END INTERFACE
CLASS Listener1 AS EVENT ' event sinks are marked AS EVENT
INTERFACE IEvents
INHERIT IUNKNOWN
AS EVENT
METHOD MyEvent(BYVAL iValue AS LONG)
PRINT "Listener1 got: "; iValue
END METHOD
END INTERFACE
END CLASS
CLASS Listener2 AS EVENT
INTERFACE IEvents
INHERIT IUNKNOWN
AS EVENT
METHOD MyEvent(BYVAL iValue AS LONG)
PRINT "Listener2 got: "; iValue
END METHOD
END INTERFACE
END CLASS
CLASS EventSource
INTERFACE IEvents ' redeclared inside the source (empty bodies)
INHERIT IUNKNOWN
METHOD MyEvent(BYVAL iValue AS LONG)
END METHOD
END INTERFACE
INTERFACE ISource
INHERIT IUNKNOWN
METHOD Trigger()
RAISEEVENT IEvents.MyEvent(42)
END METHOD
END INTERFACE
EVENT SOURCE IEvents ' this class raises IEvents events
END CLASS
FUNCTION PBMAIN() AS LONG
LOCAL src AS ISource
LOCAL l1 AS IEvents
LOCAL l2 AS IEvents
LET src = CLASS "EventSource"
LET l1 = CLASS "Listener1"
LET l2 = CLASS "Listener2"
EVENTS FROM src CALL l1 ' subscribe the listeners
EVENTS FROM src CALL l2
src.Trigger() ' raises MyEvent(42)
EVENTS END l1 ' unsubscribe
EVENTS END l2
FUNCTION = 0
END FUNCTION
Das Event-Interface wird einmal auf Modulebene deklariert. Die Quellklasse deklariert es verschachtelt erneut, ergänzt EVENT SOURCE und löst Ereignisse mit RAISEEVENT IEvents.Method(args) aus. Listener-Klassen werden mit AS EVENT deklariert. EVENTS FROM meldet einen Listener an, EVENTS END meldet ihn ab; RAISEEVENT verteilt an alle registrierten Listener über Runtime-Helfer (bestof_events_from, bestof_events_end, bestof_raiseevent_0..6). Vollständiger Regressionstest: test_class_events_multi.pb.
WITH - Block-Weitiges Member-Zugriff
WITH-Block für Kurzzugriff
#COMPILE EXE
#DIM ALL
TYPE Counter
count AS LONG
label AS STRING
END TYPE
FUNCTION PBMAIN() AS LONG
LOCAL c AS Counter
WITH c
.label = "clicks"
.count = 0
.count = .count + 1
.count = .count + 1
PRINT .label; ": "; .count ' clicks: 2
END WITH
FUNCTION = 0
END FUNCTION
WITH speichert die Variablen-Referenz und expandiert .field-Präfixe im gesamten Block, sodass der Variablenname nicht wiederholt werden muss. Es funktioniert mit TYPE-Variablen; für Interface-Objekte wird der Objektname verwendet. Die Variable wird in fn->with_var gespeichert und von den Ausdrucks- und Deklarations-Parsern genutzt.