OOP einfach gemacht

Hier könnt Ihr gute, von Euch geschriebene Codes posten. Sie müssen auf jeden Fall funktionieren und sollten möglichst effizient, elegant und beispielhaft oder einfach nur cool sein.
janroth
Beiträge: 3
Registriert: 18.04.2006 21:54
Wohnort: Uzwil/Schweiz/Kt. St.Gallen

OOP einfach gemacht

Beitrag von janroth »

Ich habe von eine einfache Anleitung für OOP im Netz gesehen. Also, all dies hier ist nicht auf meinem Mist gewachsen.

Daraus habe ich ein Beispiel gebastelt, wie man OOP in Purebasic, einfach realisieren kann.

Damit lassen sich Klassen und davon abgeleitete Objekte erzeugen.
Man kann vererben und man kann Methoden Ueberdefinieren.

Es lassen sich Objekte als Pointer auf ein Objekt im Speicher oder als normale Variable erstellen.
Objekte im Speicher kann man wieder freigeben. Die Pointervariable bleibt allerdings bestehen.

Als Konvention habe ich folgendes definiert.

Klassen Methoden beginnen immer mit dem Namen der Klasse: cMyClass_

Private Methoden beginnen immer mit __

Der *self Zeiger ist notwendig, damit die Methode weiss auf welches Objekt sie zugreifen soll.
Ganz aehnlich wie in Python nur muss der Zeiger immer mitgegeben werden.

Private Attribute beginnen immer mit __

Code: Alles auswählen

; Objektorientiert programmieren mit PureBasic

; Klassendefinition I --------------------------------------------------------

; Procedureendeklaration
Prototype cMyClass_Show(*self)
Prototype cMyClass_SetX(*self, x)
Prototype cMyClass___Clear(*self)

Structure cMyClass
  ; Public attributes
  x.l
  y.l
  ; Private attributes
  __id.l
  ; Public methods
  Show.cMyClass_Show
  SetX.cMyClass_SetX
  ; Private methods
  __Clear.cMyClass___Clear
EndStructure

; Methodendefinition

Procedure cMyClass_Show(*self.cMyClass)
  Debug *self\x
  Debug *self\y
  Debug ""
EndProcedure

Procedure cMyClass_SetX(*self.cMyClass, x.l)
  *self\x = x
EndProcedure

Procedure cMyClass___Clear(*self.cMyClass)
  *self\x = 0
  *self\y = 0
EndProcedure

; Konstruktor
Procedure cMyClass(*self.cMyClass)
  *self\Show = @cMyClass_Show()
  *self\SetX = @cMyClass_SetX()
  *self\__Clear = @cMyClass___Clear()
  *self\x = 1
  *self\y = 2
EndProcedure  

; Klassendefinition II mit Vererbung -----------------------------------------

Structure cMyNewClass Extends cMyClass
  ; Public attributes
  z.l
EndStructure

; Metodendefinition
Procedure cMyNewClass_Show(*self.cMyNewClass)
  Debug *self\x
  Debug *self\y
  Debug *self\z
  Debug ""
EndProcedure

; Konstruktor
Procedure cMyNewClass(*self.cMyNewClass)
  cMyClass(*self)                                            ; Konstruktor der Mutterklasse
  *self\z = 3
  *self\Show = @cMyNewClass_Show()
EndProcedure  

;-----------------------------------------------------------------------------

; Instanzierung

Define.cMyClass *oMyObject
*oMyObject = AllocateMemory(SizeOf(cMyClass))
cMyClass(*oMyObject)

Define.cMyNewClass oMyNewObject
cMyNewClass(oMyNewObject)

; Programmausfuehrung

*oMyObject\Show(*oMyObject)
*oMyObject\SetX(*oMyObject, 99)
*oMyObject\Show(*oMyObject)

oMyNewObject\Show(oMyNewObject)
oMyNewObject\SetX(oMyNewObject, 77)
oMyNewObject\Show(oMyNewObject)

; Objekte freigeben

FreeMemory(*oMyObject)

Eigentlich kann ma damit beinahe alles was OOP betrifft machen, was in anderen OOP-Sprachen möglich ist.

Es zeigt, wie flexibel Purebasic, als nicht OOP-Sprache, umgesetzt ist.

Viel Spass.

__________________________________________________
Code-Tags hinzugefügt
30.11.2015
RSBasic
Jan
Derren
Beiträge: 558
Registriert: 23.07.2011 02:08

Re: OOP einfach gemacht

Beitrag von Derren »

Nicht ganz so hübsch wie

Code: Alles auswählen

*obj = new cMyClass()
Aber schöner als 3 Zeilen Code :)

Code: Alles auswählen

; Instanzierung
Macro NEW(_CLASS, _OBJ)
	Define._CLASS _OBJ
	_OBJ = AllocateMemory(SizeOf(_CLASS))
	_CLASS(_OBJ)
EndMacro 

NEW(cMyClass, *myObject)
Man könnte auch folgende Macros einbauen, aber dann verliert man das schöne Syntax-Highlighting, bzw. muss es manuell dazu friemeln in den Optionen.

Code: Alles auswählen

Macro Class
	Structure 
EndMacro
 
Macro EndClass
	EndStructure
EndMacro

Class cMyClass ;Extends anotherClass
    PropertyX.i
    PropertyY.i
    MethodXY.myPrototype
EndClass
 

Habe auch schon dran rumgebastelt, ohne eine Pre-Compiler zu nutzen, aber so wirklich schön wird das leider nie :(
Signatur und so
GPI
Beiträge: 1511
Registriert: 29.08.2004 13:18
Kontaktdaten:

Re: OOP einfach gemacht

Beitrag von GPI »

Der *self Zeiger ist notwendig, damit die Methode weiss auf welches Objekt sie zugreifen soll.
Ganz aehnlich wie in Python nur muss der Zeiger immer mitgegeben werden.
da ist imo auch das größte Problem und gleichzeitig eine gewaltige Fehlerquelle.
bspw.

Code: Alles auswählen

obj1\init(obj2)
wäre möglich. Den Fehler dann später zu finden kann verflucht schwer sein.

Es gibt auch andere Probleme, nämlich das die vTable für jedes Objekt erzeugt werden muss. Das ist pro Funktion 8 Byte (4 bei 32Bit). Das kann sich sehr schnell summieren. Bei der Interface-Methode hat man die vTable nur einmal pro Klasse.

Übrigens:

Code: Alles auswählen

Define.cMyClass *oMyObject
*oMyObject = AllocateMemory(SizeOf(cMyClass))
cMyClass(*oMyObject)
Ich würde hier nicht AllocateMemory nutzen, sondern AllocateStructure. Das ermöglicht dann nämlich auch Maps und LinkedList ist den Strukturen.

Ein paar Threads weiter unten findet man mehrere Methoden, wie man OOP in PB realisieren kann:
http://www.purebasic.fr/german/viewtopi ... =8&t=29124

Sieht auf den ersten Blick etwas kompliziert aus, aber funktionieren :)

Edit: Die Methode sieht auch interessant aus:
http://www.purebasic.fr/english/viewtop ... 12&t=62356
Das löst das "*this"-Problem bei der Parameterübergabe.

Allerdings weis ich nicht, was dieser Abschnitt macht:

Code: Alles auswählen

   Macro UseInstance(This) ; provide THIS instance to module method
      CompilerIf Not Defined(_CONCAT(*th, is), #PB_Variable)
         Protected This
         CompilerIf #PB_Compiler_Processor=#PB_Processor_x64
            ! MOV [p.p_this], Rbp
         CompilerElse
            ! MOV [p.p_this], Ebp
         CompilerEndIf
      CompilerEndIf
   EndMacro
Also was er macht, ist mir klar, er findet herraus, aus welcher Variable herraus die Funktion aufgerufen wurde. Nur ist das dokumentiert? Wenn nein, ist die Lösung leider eine Zeitbombe, da Fred hier jederzeit was ändern könnte...
CodeArchiv Rebirth: Deutsches Forum Github Hilfe ist immer gern gesehen!
Antworten