Seite 1 von 1

Interface in Structure benutzen

Verfasst: 21.04.2008 12:58
von NicTheQuick
Hallo Leute,

ich weiß nicht, ob es einige hier sowieso schon so machen, aber hier ist mal
ein Beispiel, wie man sein Interface in die entsprechende Structure einbaut,
damit man auf Structure-Element gleichermaßen gut zugreifen kann wie auf
die Interface-Procedures.

Code: Alles auswählen

Interface Bruch_I
  Set(zaehler.q, nenner.q)  ;#False, wenn nenner = 0
  Double.d()
  Kehrwert()                ;#False, wenn zaehler = 0
  Kuerzen()
  Str.s()
EndInterface

Structure Bruch
  *VTable
  I.Bruch_I
  
  zaehler.q
  nenner.q
EndStructure

Macro New(Struc)
  Struc#_New()
EndMacro

Procedure Bruch_New()
  Protected *bruch.Bruch
  
  *bruch = AllocateMemory(SizeOf(Bruch))
  If Not *bruch : ProcedureReturn #False : EndIf
  
  *bruch\VTable = ?Bruch_VTable
  *bruch\I = *bruch
  *bruch\zaehler = 0
  *bruch\nenner = 1
  
  ProcedureReturn *bruch
EndProcedure

Procedure Bruch_Set(*bruch.Bruch, zaehler.q, nenner.q)
  If nenner
    *bruch\zaehler = zaehler
    *bruch\nenner = nenner
    ProcedureReturn #True
  EndIf
  
  ProcedureReturn #False
EndProcedure

Procedure.d Bruch_Double(*bruch.Bruch)
  ProcedureReturn *bruch\zaehler / *bruch\nenner
EndProcedure

Procedure Bruch_Kehrwert(*bruch.Bruch)
  If *bruch\zaehler
    Swap *bruch\zaehler, *bruch\nenner
    ProcedureReturn #True
  EndIf
  
  ProcedureReturn #False
EndProcedure

Procedure Bruch_Kuerzen(*bruch.Bruch)
  Protected k.l = 0, t.q, a.q = *bruch\zaehler, b.q = *bruch\nenner
  
  If *bruch\zaehler = 0
    *bruch\nenner = 1
    ProcedureReturn
  EndIf
  
  If *bruch\nenner < 0
    *bruch\zaehler = -*bruch\zaehler
    *bruch\nenner = -*bruch\nenner
  EndIf
  
  a = *bruch\zaehler
  If a < 0 : a = -a : EndIf
  
  b = *bruch\nenner
  While Not (a & 1 Or b & 1)
    a >> 1
    b >> 1
    k + 1
  Wend
  
  If a & 1 : t = -b : Else : t = a : EndIf
  
  While t
    While Not t & 1
      t >> 1
    Wend
    If t > 0 : a = t : t - b : Else : b = -t : t + a : EndIf
  Wend
  a << k
  *bruch\zaehler / a
  *bruch\nenner / a
EndProcedure

Procedure.s Bruch_Str(*bruch.Bruch)
  ProcedureReturn StrQ(*bruch\zaehler) + "/" + StrQ(*bruch\nenner)
EndProcedure

DataSection
  Bruch_VTable:
    Data.l @Bruch_Set(), @Bruch_Double(), @Bruch_Kehrwert(), @Bruch_Kuerzen(), @Bruch_Str()
EndDataSection

*zahl.Bruch = new(Bruch)
*zahl\zaehler = 208
*zahl\nenner = 26

Debug *zahl\I\Str()

*zahl\I\Kuerzen()
Debug *zahl\I\Str()

*zahl\I\Kehrwert()
Debug *zahl\I\Str()
Debug *zahl\I\Double()

Verfasst: 21.04.2008 20:06
von Andreas_S
Hättest du vil. einen simpleren Code? blick da nicht durch...
Also wie das interface jetzt auf die Proceduren zeigt...

Verfasst: 21.04.2008 22:08
von NicTheQuick
Die entscheidenden Zeilen befinden sich in 'Bruch_New()'. Dort wird der
Speicher für 'Bruch' reserviert und die Startwerte gesetzt. Dort weise ich
auch 'Bruch\I' den selben Pointer zu wie 'Bruch' selbst. Da aber 'Bruch\I' auf
das Interface verweist, kann man mit 'Bruch\I\Funktionname()' alle im
Interface stehenden Funktionen nutzen und ohne das 'I' auf die
Strukturelemente selbst zugreifen.

Das ist zwar nur wieder ein Trick dafür, dass es echte Klassen in PB nicht
gibt, aber es erleichtert einem die Arbeit, wenn man gerne mit Interfaces
arbeitet.

Verfasst: 24.04.2008 16:41
von mk-soft
@NicTheQuick,

Viel anders sieht es in mein OOP-PreCompiler auch nicht aus. http://www.purebasic.fr/german/viewtopi ... highlight=

Mit AllocateMemory(...) gibt es aber das Problem mit Speicherlecks bei verwendung von Strings.
Habe diese mit Linkedlist reallisiert. Siehe Ergebnis im Tempverzeichnis topfile.oop und bottomfile.oop nach den starten.

FF :wink:

Verfasst: 24.04.2008 18:02
von NicTheQuick
Deswegen nutze ich für meine Strings immer meine Stringpointer-Include,
die irgendwo im Forum rumschwirrt und auch auf meiner Seite zu finden ist.

Hab mir übrigens auch schon ein Konzept für Klassen in PB überlegt und hab
irgendwie auch Lust eine Art Precompiler zu schreiben.