Interfaces - wo mehr infos?

Anfängerfragen zum Programmieren mit PureBasic.
GPI
Beiträge: 1511
Registriert: 29.08.2004 13:18
Kontaktdaten:

Interfaces - wo mehr infos?

Beitrag von GPI »

Die Anleitung ist, um ehrlich zu sein, völlig Nutzlos und unbrauchbar. Ich hab mir folgendes zusammengereimt:

Code: Alles auswählen

;-
;- Objekt erstellen
;-

Structure _TestiInstanz
  *vtable
  meins.l
EndStructure

Interface testi
  Set(a.l)
  Get()
EndInterface

Procedure _Funk1(*obj._TestiInstanz,a.l)
  *obj\meins=a
EndProcedure

Procedure _Funk2(*obj._TestiInstanz)
  ProcedureReturn *obj\meins
EndProcedure

Procedure.i CreateTesti(startval.l=0)
  *dym._TestiInstanz=AllocateMemory(SizeOf(_TestiInstanz))
  If *dym
    *dym\vtable=?_TestiFunction
    *dym\meins=startval
  EndIf
  
  ProcedureReturn *dym
EndProcedure
Procedure.i DestroyTesti(*obj._TestiInstanz)
  If *obj
    ProcedureReturn FreeMemory(*obj)
  EndIf
  ProcedureReturn #False
EndProcedure

DataSection
  _testifunction:
  Data.i @_Funk1()
  Data.i @_Funk2()
EndDataSection
  
;-
;- Beispiel
;-

*test.testi=createtesti()
*test2.testi=createtesti(10)

Debug *test\get();0
Debug *test2\get();10
*test\set(20)
*test2\set(14)
Debug *test\get();20
Debug *test2\get();14

DestroyTesti(*test)
DestroyTesti(*test2)
Funktioniert - aber mir ist nicht klar, ob das so erlaubt ist. Ist nur wichtig, das der erste Parameter in der Structure _TestiInstanz die *vtable zu den Funktionen ist - und das wars?

Es gibt einen Hinweis auf DLL - wie läuft das dann?
CodeArchiv Rebirth: Deutsches Forum Github Hilfe ist immer gern gesehen!
Benutzeravatar
ts-soft
Beiträge: 22292
Registriert: 08.09.2004 00:57
Computerausstattung: Mainboard: MSI 970A-G43
CPU: AMD FX-6300 Six-Core Processor
GraKa: GeForce GTX 750 Ti, 2 GB
Memory: 16 GB DDR3-1600 - Dual Channel
Wohnort: Berlin

Re: Interfaces - wo mehr infos?

Beitrag von ts-soft »

Ist alles korrekt so. Wichtig ist, das die Reihenfolge im Interface der in der Datasection entspricht.
Früher mußten wir die vTable noch als Array angeben, so findet man es auch in älteren Beispielen,
aber irgendwann hat Fred ProcedurePointer in Datasection ermöglicht.

Wenn jemand aus der Objecterstellungsprocedure ein .DLL gemacht hat, dann nur um die Erstellung
einer UserLib mit TailBite zu erleichtern, bzw. anzudeuten, das dies die einzig direkt zu nutzende
Funktion ist!

Gruß
Thomas

// edit
Hier noch ein Tutorial von srod:
http://www.purecoder.net/oop.zip
PureBasic 5.73 LTS | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Nutella hat nur sehr wenig Vitamine. Deswegen muss man davon relativ viel essen.
Bild
GPI
Beiträge: 1511
Registriert: 29.08.2004 13:18
Kontaktdaten:

Re: Interfaces - wo mehr infos?

Beitrag von GPI »

Danke hab mir jetzt mal folgendes gebastelt

Code: Alles auswählen

;-
;- Objekt erstellen
;-

Structure _testi_Instanz
  *vtable
  meins.l
EndStructure

Interface testi
  _Create()
  _Destroy()
  Set(a.l)
  Get()
EndInterface

Procedure _create(*obj._testi_Instanz)
  Debug "...Neues Object erstellt"
EndProcedure
Procedure _destroy(*obj._testi_Instanz)
  Debug "...Object zerstört"
EndProcedure

Procedure _Funk1(*obj._testi_Instanz,a.l)
  *obj\meins=a
EndProcedure

Procedure _Funk2(*obj._testi_Instanz)
  ProcedureReturn *obj\meins
EndProcedure

DataSection
  _testi_function:
  Data.i @_create()
  Data.i @_destroy()
  Data.i @_Funk1()
  Data.i @_Funk2()
EndDataSection
  
;-
;- Macros zum Aufruf
;-
Macro OOPNew(vari,typ)
  vari.typ, __#vari._#typ#_Instanz
  If vari=0
    vari=@__#vari
    __#vari\vtable=?_#typ#_function
    vari\_create()
  EndIf
EndMacro
Macro OOPClear(vari,typ)
  vari\_destroy()
  FillMemory(@__#vari+SizeOf(vari), SizeOf(_#typ#_Instanz)-SizeOf(vari) )  
  vari\_create()
EndMacro
Macro OOPNewClear(vari,typ)
  vari.typ, __#vari._#typ#_Instanz
  If vari
    vari\_destroy()
    FillMemory(@__#vari+SizeOf(vari), SizeOf(_#typ#_Instanz)-SizeOf(vari) )  
  Else
    vari=@__#vari
    __#vari\vtable=?_#typ#_function
  EndIf
  vari\_create()
EndMacro
Macro OOPCopy(vari,varb)
  CopyMemory(@__#vari,@__#varb,SizeOf(__#vari))
EndMacro
Macro OOPDelete(vari)
  vari\_destroy()
  vari=0
EndMacro

Macro OOPNewList(vari,typ,def=)
  def NewList vari.typ()
  def NewList __#vari._#typ#_Instanz()
EndMacro
Macro OOPAddElement(vari,typ)
  AddElement(vari())
  AddElement(__#vari())
  vari()=@__#vari()
  __#vari()\vtable=?_#typ#_function
  vari()\_create()
EndMacro
Macro OOPDeleteElement(vari)
  vari()\_destroy()
  ChangeCurrentElement(__#vari(), vari())
  DeleteElement(vari())
  DeleteElement(__#vari())
EndMacro
Macro OOPClearList(vari)
  ForEach vari()
    vari()\_destroy()
  Next
  ClearList(vari())
  ClearList(__#vari())
EndMacro
Macro OOPFirstElement(vari)
  FirstElement(vari())
EndMacro
Macro OOPFreeList(vari)
  ForEach vari()
    vari()\_destroy()
  Next
  FreeList(vari())
  FreeList(__#vari())
EndMacro
Macro OOPInsertElement(vari,typ)
  InsertElement(vari())
  InsertElement(__#vari())
  vari()=@__#vari()
  __#vari()\vtable=?_#typ#_function
  vari()\_create()
EndMacro
Macro OOPLastElement(vari)
  LastElement(vari())
EndMacro  
Macro OOPListIndex(vari)
  ListIndex(vari())
EndMacro
Macro OOPListSize(vari)
  ListSize(vari())
EndMacro
Macro OOPNextElement(vari)
  NextElement(vari())
EndMacro
Macro OOPPreviousElement(vari)
  PreviousElement(vari())
EndMacro
Macro OOPResetList(vari)
  ResetList(vari())
EndMacro
Macro OOPSelectElement(vari,b)
  SelectElement(vari(),b)
EndMacro
Macro OOPChangeCurrentElement(vari,b)
  ChangeCurrentElement(vari(),b)
EndMacro
Macro OOPSwapElements(vari,a,b)
  SwapElements(vari(),a,b)
EndMacro

;-
;- beispiele
;-

Procedure AProc(b)
  OOPNewList(AProList,testi,Static)
  OOPClearList(AProList)
  For i=1 To 10
    OOPAddElement(AProList,testi)
    AProList()\Set(b*I)
  Next
  ForEach AProList()
    Debug AProList()\Get()
  Next
EndProcedure

Debug "-"
Debug "- Static-Procedure-Test"
Debug "-"
Debug "Aufruf 1:"
AProc(1)
Debug "Aufruf 2:"
AProc(2)

Debug "-"
Debug "- Global List"
Debug "-"


OOPNewList(liste,testi,Global)
OOPAddElement(liste,testi)
liste()\set(1)
OOPAddElement(liste,testi)
liste()\set(2)
i=10
ForEach liste()
  oopaddelement(Liste,testi)
  liste()\set(i):i+1
Next

Debug "test1"
ForEach liste()
  Debug liste()\get()
  If liste()\get()=10
    OOPDeleteElement(liste)
  EndIf
  
Next
oopaddelement(liste,testi)
liste()\set(99)

Debug "test2"
ForEach liste()
  Debug liste()\get()
Next

Debug "test3 - 10 sollte jetzt nicht mehr da sein"
ForEach __liste()
  Debug __liste()\meins
Next

oopfreelist(liste)

Debug "----"

Define OOPnew(test,testi)
Define OOPnew(test2,testi)
Define OOPNew(test2,testi)

test\set(10)
test2\set(40)
Debug "--10,40"
Debug test\get()
Debug test2\get()

OOPCopy(test,test2)
Debug "--10,10"
Debug test\get()
Debug test2\get()

Debug "--10,30"
test2\set(30)
Debug test\get()
Debug test2\get()

OOPDelete(test)
OOPDelete(test2)
Die Macros sind so gestalltet, das man damit verschiedene "Interfaces" damit abdecken kann - wenn man die Namenskonventionen beibehält. Weiterer Vorteil: Automatischer Aufruf von _create() und vorallen _destroy(). Praktisch, wenn man Speicher oder andere Handles in den Objekt erstellt hat.

Größtes Problem an der ganzen Sache ist wohl, das PureBasic kein "_Destroy()" aufruft, wenn ein "OOP-Objekt" freigegeben wird. (Bspw. wenn es ein Protected-Variable innerhalb einer Prozedure ist) Das kann meiner Meinung nach zu einen bösen Speicherleck führen. Hier ist wirklich viel Programmierdisziplin gefordert. Meine Macros nutzen zumindest normale Variablen zum Speichern - wenn ein Objekt also keine Handles öffnet oder kein Speicher reserviert, dann gibts hier kein Speicherlecks...

Meine Empfehlung ist da wirklich, solche Objekte als Static oder Global zu benutzen - solange man eine Funktion nicht Rekursiv (=sich selbst aufrufend) braucht, sollte das kein Problem sein. Dann kann man einfach durch sowas:

Code: Alles auswählen

 OOPNewList(AProList,testi,Static)
  OOPClearList(AProList)
Sollten in der Liste noch von Letzen mal Objekte vorhanden sein, würden sie jetzt ordnungsgemäß freigegeben.

Code: Alles auswählen

 Static OOPNewClear(meins,testi)
Genauso hier: Wenn es Meins schon gab, dann wird es freigeben und gelöscht und ein neues erstellt.

Was man halt auch wissen muss, bei den Macros wird immer eine zusatzvariable/liste mit __ an Anfang erstellt.
CodeArchiv Rebirth: Deutsches Forum Github Hilfe ist immer gern gesehen!
Antworten