Procedure vorhanden?

Für allgemeine Fragen zur Programmierung mit PureBasic.
Benutzeravatar
Olafmagne
Beiträge: 140
Registriert: 07.12.2017 17:30
Wohnort: Sete/Frankreich

Re: Procedure vorhanden?

Beitrag von Olafmagne »

Nun, eine BaseClass könnte zB Methoden haben, die nicht verändert werden dürfen, in der Regel als <Static> markierte( Static ist ein KeyWord in PB, deshalb bei mir <Definitiv>)
Dann könnte es nötig sein eine Bestimmte Function zu haben, zB weil eine andere Function Darauf zugreift, aber jetzt noch nicht implementiert werden kann, sondern von den ChildClass geliefert wird, in der BaseClass aber definiert, diese sind <Abstract>.
Dann sind noch Functionen, die überschriben werden können, diese sind <Virtuell> karkiert.

Das soll in der BaseClass gemacht werden und ist eigendlich ein Eintrag in einer Map (via Macro)
Diese Maps sind Public und können mit zB BaseClass::Abstract(. . .). . . eingesehen werden und . . .

Ok, soweit bin ich schon. Ziel ist es, zB ein überschreiben einer <Definitiv>Function zu verhindern(Error), ein überschreiben einer <Acstract)Function zu "fordern" sonst(Error)
und sicherzustellen, dass <Virtuell> selbstständig überschrieben wird.
Ich gehe davon aus, dass derjenige, der eine ChildClass schreibt weiss, welche Functionen in der BaseClass sind und auch Ihren Status kennt.
Das heisst, zu überschreibende Functionen dürfen nicht im Interface erscheinen, Sie sind ja schon in der BaseClass und dürfen in der ChildClass nur implementiert werden.
Zu <Virtuel>, hier sind nicht nur die Functionen der BaseClass zu markieren, sondern auch in der ChildClass,(Soll sie überschrieben werden?, oder ist sie zwar implementiert, aber in diesem Fall nicht benötigt)
Ich denke, dass es Situationen gibt, in denen die Base-Function gebraucht wird und Situationen, in denen diese Function überschrieben werden soll.

An diesem Punkt bin ich gerade

Ach ja, Überladen kann mann auch simulieren, gell!
Code dazu kommt später, muss erst mal zum TÜV . . .
Unsinnige Anweisungen von Seiten des Chef's lösen grundsätzlich ein "Syntax Error" bei mir aus
OS=Linux Zorin
PureBasic 6.xx
SMaag
Beiträge: 184
Registriert: 08.05.2022 12:58

Re: Procedure vorhanden?

Beitrag von SMaag »

Ich hab jetzt mal einen DemoCode erstellt.
Vereerbung funktioniert, überschreiben auch!

OOP:: enthält die Methoden von IUnknown

Parent:: implementiert dann IUnknown und erweitert es
Child: implementiert IParent und erweitert es. In Child wird dann eine eigene MethodeA() erstellt, welche Parent\MethodeA() überschreibt

Die VTable wurde mit einem Public Array realisiert, damit man die Methodenadressen einfach in die abgeleitete Klasse kopieren kann!

Code: Alles auswählen


; update: missing  Pointer *This fixed
; update: added Macro Implement_VTable
; update: VTable Definition As Byte

DeclareModule OOP
  
; IUnknown ist in PB bereits definiert
;   Interface IUnknown  
;     ; IUnknown
;     QueryInterface(*riid, *addr)
;     AddRef()
;     Release()
;   EndInterface
  
  Structure TThis
    ; iUnknown
    *vTable     ; Pointer to VirtalMethodeTable (Addresslist of Methodes declared in the Interface)
    cntRef.i    ; Object reference counter
    objMutex.i  ; Object Mutex! Only if object used by different treads! It shows that Object is in operation by a thread!
  EndStructure
  
  Global Dim VTable.a(SizeOf(IUnknown)-1)
  
  Macro IUnknownToVTable
    CopyMemory(OOP::@VTable(), @VTable(), SizeOf(IUnknown))
  EndMacro
  
  Macro InterfaceToVTable(ModuleName, InterfaceName)
    CopyMemory(ModuleName::@VTable(), @VTable(), SizeOf(ModuleName::InterfaceName))
  EndMacro
  
EndDeclareModule

Module OOP
  
  EnableExplicit
  ; ======================================================================
  ;  Implement the Methodes of iUnknown
  ; ======================================================================

  ; QueryInterface : part of iUnknown, for PureBasic only it's not needed
  Procedure QueryInterface(*This.TThis, *riid, *addr)
    ProcedureReturn $80004002 ; (#E_NOINTERFACE)
  EndProcedure
  
  Procedure AddRef(*This.TThis)
  ; ======================================================================
  ; Increment the ReferenceCounter! This is used if you do Multithreading
  ; and access 1 ObjectInstance from 2 different Threads
  ; in VB6/VBA we can't to this because it is single threading only!
  ; in PureBasic we can use Multitherading with language integrated
  ; command CreateThread() 
  ; ======================================================================

    If *This
      LockMutex(*This\objMutex)
      *This\cntRef + 1
      UnlockMutex(*This\objMutex)
      ProcedureReturn *This\cntRef
    Else
      ProcedureReturn 0
    EndIf
  EndProcedure
  
  Procedure Release(*This.TThis)
  ; ======================================================================
  ; Decrement the ReferenceCounter! Destroy the object?
  ; If we do Multithreading and the object is referenced by more than 1
  ; Thread, only the reference counter will be decremented. 
  ; If it is the last reference to the object it will be destroyed.
  ; This is the normal way for single threaded programms were we have
  ; only 1 reference!  
  ; ======================================================================

    If *This
      With *This
        LockMutex(\objMutex)
        If \cntRef = 1  ; If it is the last reference THEN delete the object
          ; 
          ; Maybe further operations here for cleanup
          ; ---
          ; Dispose(*this)
          ; ---
          FreeMutex(\objMutex)    ; Delete the Mutes
          FreeStructure(*This)    ; Relase the allocated memory; kill the instance
          
          ProcedureReturn 0
          
        Else
          \cntRef - 1 ; Decrement No of referenced threads
        EndIf
        UnlockMutex(\objMutex)
      EndIf
        ProcedureReturn \cntRef
    EndWith
  EndProcedure
  
  ; Write Methodes Address into VTable
  PokeI(@VTable() + OffsetOf(IUnknown\QueryInterface()), @QueryInterface() )
  PokeI(@VTable() + OffsetOf(IUnknown\AddRef()), @AddRef() )
  PokeI(@VTable() + OffsetOf(IUnknown\Release()), @Release() )
  
  Debug "VTable Adress of IUnknown"
  Debug @VTable()
  Debug @VTable(0)
  
EndModule

; ********************************************************************************

DeclareModule Parent
  
  Interface IParent Extends IUnknown
    MethodeA(a1.i)
    MethodeB(b1.i)
  EndInterface

  Structure TThis Extends OOP::TThis   ; This is the Structure for the Class Instance Data
    mName.s
  EndStructure

  Global Dim VTable.a(SizeOf(IParent)-1)
 
  Macro Implement_VTable
    ;CopyMemory(Parent::@VTable(), @VTable(), SizeOf(Parent::IParent))
    OOP::InterfaceToVTable(Parent, IParent)
  EndMacro

  Declare.i New()     ; Public Procedure to create new instance 
  
EndDeclareModule

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

Module Parent
  
  EnableExplicit
  
  ; Anzahl der Einträge in der VTable
  ; Debug "SizeOfInteface " + Str(SizeOf(IParent)/SizeOf(Integer))
        
  Procedure MethodeA(*This.TThis, a1.i)
     Debug "Parent MethodeA a1= " + Str(a1)
  EndProcedure 
  
  Procedure MethodeB(*This.TThis, b1.i) 
     Debug "Parent MethodeB b1 = " + Str(b1)    
  EndProcedure 
  
  
  Procedure New() 
  ; ======================================================================
  ;   Creates a New Instance of the ClassObject
  ;   it Returns the Pointer to the allocated memory or
  ;   0 if it couldn't get the memory from OS
  ; ======================================================================
    
    Protected *obj.TThis
    
    ; Schritt 1: Speicher anfordern. Dazu bietet sich AllocateStructure an, weil diese auch den Speicher initialsiert
    *obj = AllocateStructure(TThis)
    
    ; Schritt 2: Erforderlich Zeiger setzen und Mutex anlegen. Aber nur wenn Speicher vorhanden ist (Out Of Memory ?)
    If *obj
      *obj\vTable = @VTable(0)            ; Zeiger auf die Funktionstabelle setzen (Methoden). Siehe weiter unten.
      *obj\objMutex = CreateMutex()       ; Mutex zum Schutz des RefCounter anlegen, kann auch in den Funktionen verwendet werden
                                          ; Zum Beipiel wenn auf das Objekt aus verschiedenen Threads zugegriffen wird
      *obj\cntRef = 1                
      ; Eventuelle weitere Zuweisungen. Zum Beipiel eine New-Funktion mit Parametern
      
     EndIf
    
    ProcedureReturn *obj
  EndProcedure
  
  ; Implement IUnknown
  ;CopyMemory(OOP::@VTable(), @VTable(), SizeOf(IUnknown))
  OOP::IUnknownToVTable 
  
  ; Write Methodes Address into VTable
  PokeI(@VTable() + OffsetOf(IParent\MethodeA()), @MethodeA() ) 
  PokeI(@VTable() + OffsetOf(IParent\MethodeB()), @MethodeB())

EndModule

; ********************************************************************************

DeclareModule Child
  
  Interface IChild Extends Parent::IParent
     MethodeC(c1.i)
  EndInterface
  
  Structure TThis Extends Parent::TThis   ; This is the Structure for the Class Instance Data
                                          ; MyClassData
  EndStructure
  
  Global Dim VTable.a(SizeOf(IChild)-1)
 
 Macro Implement_VTable
    ;CopyMemory(IChild::@VTable(), @VTable(), SizeOf(Child::IChild))
    OOP::InterfaceToVTable(Child, IChild)

  EndMacro

  Declare.i New()     ; Public Procedure to create new instance 
  
EndDeclareModule

Module Child
  EnableExplicit
    
  ; ======================================================================
  ;  Implements the Methodes of iUnknown
  ; ======================================================================
  
  ; Implement a new MethodeA for Child => tp overwrite Parent\MethodeA
  Procedure MethodeA(*This.TThis, a1.i)
     Debug "Child MethodeA a1= " + Str(a1)
  EndProcedure
    
  Procedure MethodeC(*This.TThis, c1.i)
     Debug "Child MethodeC c1 = " + c1
  EndProcedure 
  
  Procedure New() 
  ; ======================================================================
  ;   Creates a New Instance of the ClassObject
  ;   it Returns the Pointer to the allocated memory or
  ;   0 if it couldn't get the memory from OS
  ; ======================================================================
    
    Protected *obj.TThis
    
    ; Schritt 1: Speicher anfordern. Dazu bietet sich AllocateStructure an, weil diese auch den Speicher initialsiert
    *obj = AllocateStructure(TThis)
    
    ; Schritt 2: Erforderlich Zeiger setzen und Mutex anlegen. Aber nur wenn Speicher vorhanden ist (Out Of Memory ?)
    If *obj
      *obj\vTable = @VTable()             ; Zeiger auf die Funktionstabelle setzen (Methoden). Siehe weiter unten.
      *obj\objMutex = CreateMutex()       ; Mutex zum Schutz des RefCounter anlegen, kann auch in den Funktionen verwendet werden
                                          ; Zum Beipiel wenn auf das Objekt aus verschiedenen Threads zugegriffen wird
      *obj\cntRef = 1                
      ; Eventuelle weitere Zuweisungen. Zum Beipiel eine New-Funktion mit Parametern
      
     EndIf
    
    ProcedureReturn *obj
  EndProcedure
  
  ; Implement IParent
  ;CopyMemory(Parent::@VTable(), @VTable(), SizeOf(Parent::IParent))
  Parent::Implement_VTable
  
  ; Write Methodes Address into VTable
  PokeI(@VTable() + OffsetOf(IChild\MethodeC()), @MethodeC() )
  
  ; Overwrite Parent\MethodA with Cild\MethodeA
  PokeI(@VTable() + OffsetOf(IChild\MethodeA()), @MethodeA() )
EndModule

; Testcode

Global *MyParent.Parent::IParent  ; Object of BaseClass
Global *MyChild.Child::IChild    

*MyParent = Parent::New() 
*MyChild = Child::New()

Debug #Null$
Debug "Call Parent Methodes"
*MyParent\MethodeA(1)
*MyParent\MethodeB(2)

Debug #Null$
Debug "Call Child Methodes"
*MyChild\MethodeA(3)    ; here Child\MethodeA is called because of overwrite
*MyChild\MethodeB(4)    ; here Parent\MethobeB is called (not overwritten)
*MyChild\MethodeC(5)
Zuletzt geändert von SMaag am 04.08.2023 16:50, insgesamt 2-mal geändert.
Benutzeravatar
mk-soft
Beiträge: 3855
Registriert: 24.11.2004 13:12
Wohnort: Germany

Re: Procedure vorhanden?

Beitrag von mk-soft »

Die Bezeichnung Parent und Client für Vererbung ist hier nicht passend und hat eine andere Bedeutung in der OOP Programmierung.
Es ist besser hier über Basis Klasse und Sub Klasse zu sprechen ...

Siehe Beschreibung: viewtopic.php?t=29343

Parent und Client:
Ein Parent ist ein eigenes Objekt und ein Client ist eigenes Objekt mit einen verweis auf das Parent Objekt.
ein Client Objekt kann auch wieder ein Client Objekt haben, wobei der Parent Verweis auf das vorherige Client Objekt ist.
Dieses in PB zu erstellen ist möglich, aber sehr aufwendig.
Alles ist möglich, fragt sich nur wie...
Projekte ThreadToGUI / EventDesigner V3 / OOP-BaseClass-Modul
Downloads auf MyWebspace / OneDrive
SMaag
Beiträge: 184
Registriert: 08.05.2022 12:58

Re: Procedure vorhanden?

Beitrag von SMaag »

Code: Alles auswählen

Die Bezeichnung Parent und Client für Vererbung ist hier nicht passend und hat eine andere Bedeutung in der OOP Programmierung.
Es ist besser hier über Basis Klasse und Sub Klasse zu sprechen ...
ja, ist klar!

Ich hatte leider auch nicht bemerkt, dass es im englischen Forum bereits einen größeren Beitrag mit Code dazu gibt, der bereits funktioniert!
Damit ist die Diskussion eigentlich hinfällig. Ich dachte es geht noch um die Grundlagen, das hinzubekommen.

Hab mir das angesehen:
so ist das natürlich schon recht komfortabel und durch die die Makros wie AsMethode() usw. wird die Fehlernafälligkeit beim hantieren
mit den VTable Pointer praktisch ausgeschlossen. Leider recht dürftig dokumentiert und durch die vielen Makros und Verschachtelung nur schwer durchschaubar!
Zuletzt geändert von SMaag am 04.08.2023 19:27, insgesamt 1-mal geändert.
Benutzeravatar
Olafmagne
Beiträge: 140
Registriert: 07.12.2017 17:30
Wohnort: Sete/Frankreich

Re: Procedure vorhanden?

Beitrag von Olafmagne »

Da ist eine neue Frage aufgetaucht:
Was ist dieses IUnknown-Interface?
Ich habe darüber keine Infos finde können.
Unsinnige Anweisungen von Seiten des Chef's lösen grundsätzlich ein "Syntax Error" bei mir aus
OS=Linux Zorin
PureBasic 6.xx
Benutzeravatar
mk-soft
Beiträge: 3855
Registriert: 24.11.2004 13:12
Wohnort: Germany

Re: Procedure vorhanden?

Beitrag von mk-soft »

Olafmagne hat geschrieben: 04.08.2023 18:12 Da ist eine neue Frage aufgetaucht:
Was ist dieses IUnknown-Interface?
Ich habe darüber keine Infos finde können.
MSDN:
https://learn.microsoft.com/de-de/windo ... nheritance
https://learn.microsoft.com/de-de/windo ... n-iunknown

WIKI:
https://de.wikipedia.org/wiki/Component_Object_Model
Alles ist möglich, fragt sich nur wie...
Projekte ThreadToGUI / EventDesigner V3 / OOP-BaseClass-Modul
Downloads auf MyWebspace / OneDrive
SMaag
Beiträge: 184
Registriert: 08.05.2022 12:58

Re: Procedure vorhanden?

Beitrag von SMaag »

nochmal zum Code von BaseClass aus dem englischen Forum.

wie schon gesagt im Detail schwierig zu kapieren!
dazu einige Fragen

Structure udtClass
Array *vTable(3)
Array Initialize.udtInvoke(0)
Array Dispose.udtInvoke(0)
*Package.sPackage
EndStructure

1. was für eine Struktur ist sPackage, ist wieder nirgends zu finden, auch nicht im StructurViewer!
Muss wieder was in PB implementiert sein, da es keinen Fehler gibt! Komischer Weise kann man
sPackage nur innerhalb einer Structure verwenden sonst gibt es Fehler

2. Warum ist Initialize und Dispose ein Array
Je Klasse gibt es doch eigentlich nur eine Methode für Initialize und Dispose
Welchen Sinn macht es mehrere zu haben?
Benutzeravatar
Olafmagne
Beiträge: 140
Registriert: 07.12.2017 17:30
Wohnort: Sete/Frankreich

Re: Procedure vorhanden?

Beitrag von Olafmagne »

@mk-soft
OK, IUnknown ist reiner Windowskram.
Dann sollte ich das nicht brauchen, da ich meine eigenen Klassen schreiben möchte und möglichst unabhängig von einem bestimmten System (auch wenn das ein oder andere sinnvoll ist, wenn es auf allen OS Ähnliches gibt) sein möchte.
Unsinnige Anweisungen von Seiten des Chef's lösen grundsätzlich ein "Syntax Error" bei mir aus
OS=Linux Zorin
PureBasic 6.xx
Benutzeravatar
mk-soft
Beiträge: 3855
Registriert: 24.11.2004 13:12
Wohnort: Germany

Re: Procedure vorhanden?

Beitrag von mk-soft »

SMaag hat geschrieben: 04.08.2023 19:35 nochmal zum Code von BaseClass aus dem englischen Forum.

wie schon gesagt im Detail schwierig zu kapieren!
dazu einige Fragen

Structure udtClass
Array *vTable(3)
Array Initialize.udtInvoke(0)
Array Dispose.udtInvoke(0)
*Package.sPackage
EndStructure

1. was für eine Struktur ist sPackage, ist wieder nirgends zu finden, auch nicht im StructurViewer!
Muss wieder was in PB implementiert sein, da es keinen Fehler gibt! Komischer Weise kann man
sPackage nur innerhalb einer Structure verwenden sonst gibt es Fehler

2. Warum ist Initialize und Dispose ein Array
Je Klasse gibt es doch eigentlich nur eine Methode für Initialize und Dispose
Welchen Sinn macht es mehrere zu haben?
Zu 1.
Package ist ein Zeiger auf Globale Daten die über alle Objekte von der Klasse gemeinsam sind. Hier kann man zum Beispiel ein Objekt Zähler hinterlegen.
Den Inhalt des Daten Struktur 'sPackage' legt man selber fest. Wenn es diese nicht gibt ignoriert PB diese Struktur.
Beispiel 4: https://www.purebasic.fr/english/viewto ... 92#p555092

Zu 2.
Eine Mehrfachvererbung ist ja möglich. Somit kann auch die Klasse eine Initialize und Dispose besitzen die mit Vererbt wird und auch aufgerufen werden muss.
Bei der ersten Klasse erbt man die BaseClass und legt die Methoden und die Initialize, Dispose an.
Jetzt kann diese Klasse wieder vererbt werden und die erweiterten Methoden und die zusätzliche Initialize, Dispose hinzufügen.
Alles ist möglich, fragt sich nur wie...
Projekte ThreadToGUI / EventDesigner V3 / OOP-BaseClass-Modul
Downloads auf MyWebspace / OneDrive
Benutzeravatar
mk-soft
Beiträge: 3855
Registriert: 24.11.2004 13:12
Wohnort: Germany

Re: Procedure vorhanden?

Beitrag von mk-soft »

Olafmagne hat geschrieben: 04.08.2023 20:25 @mk-soft
OK, IUnknown ist reiner Windowskram.
Dann sollte ich das nicht brauchen, da ich meine eigenen Klassen schreiben möchte und möglichst unabhängig von einem bestimmten System (auch wenn das ein oder andere sinnvoll ist, wenn es auf allen OS Ähnliches gibt) sein möchte.
Das stimmt, aber die Methoden AddRef und Release werden auch jedem fall benötigt. Da kann man auch gleich die QuerInterface mitliefern
(Was ich auch mal bei Windows benötigte)
Alles ist möglich, fragt sich nur wie...
Projekte ThreadToGUI / EventDesigner V3 / OOP-BaseClass-Modul
Downloads auf MyWebspace / OneDrive
Antworten