vb@rchiv
VB Classic
VB.NET
ADO.NET
VBA
C#
Brandneu! sevEingabe v3.0 - Das Eingabecontrol der Superlative!  
 vb@rchiv Quick-Search: Suche startenErweiterte Suche starten   Impressum  | Datenschutz  | vb@rchiv CD Vol.6  | Shop Copyright ©2000-2024
 
zurück
Rubrik: Variablen/Strings · UDT (Benutzerdefinierte Datentypen)   |   VB-Versionen: VB611.05.05
UDT als Parameter einer Klassen-Prozedur III

Das Schlüsselwort FRIEND bei Methoden und Eigenschaften

Autor:   Manfred BohnBewertung:     [ Jetzt bewerten ]Views:  14.766 
ohne HomepageSystem:  Win9x, WinNT, Win2k, WinXP, Win7, Win8, Win10, Win11kein Beispielprojekt 

Korrekturhinweis zum Tipp 1231 "UDT als Parameter einer Klassenprozedur'" per API-Funktion "rtlMoveMemory"

Der Tipp  UDT als Parameter einer Klassen-Prozedur ist irreführend.

Bei der Festlegung des Geltungsbereichs von Prozeduren in Klassenmodulen stellt VB6 drei Möglichkeiten zur Verfügung:

  1. Das Schlüsselwort 'Private' führt bei Prozeduren dazu, dass die Methode/Eigenschaft nur innerhalb der Klasse 'sichtbar' ist, in der die Prozedur deklariert ist.
  2. Das Schlüsselwort 'Friend' sorgt dafür, dass die Methode/Eigenschaft innerhalb der gesamten ActiveX-Komponente sichtbar wird, innerhalb der die Prozedur deklariert ist.
  3. Die Verwendung des Schlüsselworts 'Public' bei Prozeduren in Klassen, deren Instancing-Eigenschaft auf 'PublicNotCreatable' oder auf 'MultiUse' eingestellt ist, macht die Methode/Eigenschaft für den Zugriff aus anderen ActiveX-Objekten verfügbar.

Bei Klassen in Standard-Exe Projekten ist prinzipiell die Instancing-Eigenschaft 'Private'. Andere ActiveX-Objekte können nicht auf solche Klassen zugreifen. Dem EXE-Projekt fehlt ja die ActiveX-Umgebung. Es kann zwar selber ActiveX-Objekte ankoppeln - aber nicht an andere angekoppelt werden.

Insofern ist das Schlüsselwort 'Public' für Prozeduren in Klassen, die in Standard-Exe-Projekten definiert sind, eigentlich sinnlos. Genau genommen werden deren Prozeduren wie 'Friend' behandelt, weil sie nur innerhalb des Projekts sichtbar sind.

Aus dem Abschnitt 'Friend-Eigenschaften und -Methoden' in der VB6-Dokumentation:
Standard-EXE-Projekte können keine ActiveX-Komponenten sein, da ihre Klassenmodule nicht öffentlich sein können und deshalb nicht von anderen Anwendungen verwendet werden können. Jegliche Kommunikation zwischen Objekten in einem Standard-EXE-Projekt ist daher privat, und es besteht keine Notwendigkeit für Friend-Elemente. Friend-Elemente haben jedoch ein besonders nützliches Merkmal. Da sie nicht Teil einer ActiveX-Schnittstelle sind, lassen sie sich für das Übergeben von benutzerdefinierten Datentypen zwischen Objekten einsetzen, ohne daß sie öffentlich offengelegt werden.

Soweit die Dokumentation.

Damit wird die Lösung des Problems erkennbar.
Man deklariert seine Klassen-Prozeduren mit dem Schlüsselwort 'Friend', weil das Schlüsselwort 'Public' den Compiler irritiert und er deshalb eine in Standard-Exe-Projekten nicht passende Fehlermeldung ausgibt.
Der Compiler geht vermutlich davon aus, er sei in einer ActiveX-Umgebung, sobald er eine 'Public'-Klasse übersetzen soll. Derartige Klassen dürfen aber nicht von Standardmodulen, sondern nur von anderen ActiveX-Objekten abhängig sein (vgl. Tipp 1252).

In Standard-Exe-Projekten akzeptieren als 'Friend' deklarierte Klassenprozeduren öffentliche UDTs, die in Standardmodulen definiert sind!!
Ich empfehle deshalb, den Tipp 1231 durch einen Hinweis auf das Schlüsselwort 'Friend' zu ersetzen.

Bei der Deklaration von Ereignissen ist das Schlüsselwort 'Friend' nicht zulässig. Hier muss man sich tatsächlich mit der Ausgabe eines Pointers auf eine Variable des Datentyps behelfen und mit rtlMoveMemory kopieren, wie es in Tipp 1231 vorgemacht wird, was aber nur bei elementaren numerischen Datentypen zu empfehlen ist.

Einige weitere nützliche Hinweise:

Der Nachteil der Deklaration von Klassen-Prozeduren als 'Friend' besteht darin, dass auf sie nicht von anderen AktiveX-Objekten zugegriffen werden kann.
Verwendet man statt dessen 'Public' in Prozedur-Deklarationen kann die gleiche Klasse parallel verwendet werden: mit Einstellung Instancing=Private in Standard-Exe-Projekten und mit Einstellung Instancing=Multiuse ohne Einschränkung komponentenübergreifend in AktiveX-Projekten.

Zudem gilt:
In einer objektorientierten Sprache wie Visual Basic sollte man keine Datentypen an Objekte übergeben (schlechter Stil), sondern besser aus solchen Datentypen Klassenmodule machen.
Erforderliche Schritte:

  1. Datentyp im Deklarationsteil eines Klassenmoduls 'Private' festlegen
  2. Private klassenglobale Zugriffsvariable dieses Datentyps (im Deklarationsteil der Klasse) deklarieren
  3. geeignete Property-Prozeduren für die einzelnen Elemente des Datentyps im Klassenmodul ergänzen.

Klassen bieten gegenüber Datentypen zahlreiche Vorteile (die Initialisierung, díe Überwachung der Zuweisungen in Property-Prozeduren, die Definition von Ereignissen u.v.a.).

Beispiel:

  1. Neues Standard-Exe-Projekt anlegen
  2. Standardmodul Module1 hinzufügen
  3. Klassenmodul Class1 hinzufügen

' ---------------------------------------------------------
' Code bitte in das Start-Formular Form1 einfügen
 
Option Explicit
 
' Kopierfunktion Windows-API
Private Declare Sub CopyMemory Lib "kernel32" _
  Alias "RtlMoveMemory" ( _
  ByVal Addr As Long, _
  ByVal source As Long, _
  ByVal bytes As Long)
 
' Zugriffsvariable zu einer Instanz der Klasse (mit Ereignissen)
Dim WithEvents cl As Class1
Sub cl_Meldung(ByVal pointer As Long)
  ' Ereignis
  ' (ausgelöst von Instanz cl des Klassenmoduls class1)
 
  Dim t As MyTyp
 
  ' WARNUNG: Variable vom Typ String (Deskriptor-Kopie)
  ' sowie variable Arrays können hier ernste Probleme machen !!!!
  ' Die Anwendung ist deshalb nur bei numerischen Datentypen
  ' zu empfehlen
  CopyMemory VarPtr(t), pointer, Len(t)
 
  With t
    MsgBox "Meldung: " + vbCrLf + .comment + vbCrLf + _
     .s + vbCrLf + CStr(.v) + vbCrLf + CStr(.z) + vbCrLf + CStr(.d) + vbCrLf + .st.s
  End With
End Sub
Private Sub Form_Load()
  ' Formular anzeigen
  Me.Show
 
  ' Instanz der Klasse erstellen
  Set cl = New Class1
 
  ' Variable des Demotyps in 'Module1' deklarieren
  Dim t As MyTyp
 
  ' Variable mit Werten füllen
  With t
    .v = CDec("100,123")
    .s = "was man als Typ so braucht"
    .d = -1234567890.12346
    .z = CDate("22:45:18")
    ' einige Werte des Untertyps füllen
    .st.z = CDate("14:20:25")
    .st.s = "Untertyp"
 
    .comment = "Ich möchte in cl eingetragen werden"
  End With
 
  ' Zuweisung der Eigenschaft (geschieht automatisch ByVal)
  cl.Eigenschaft = t
 
  ' der Inhalt des Elements 'Comment' hat sich nicht geändert
  ' obwohl in der Property eine Zuweisung erfolgt ist
  Debug.Print "Formular: "; t.comment
 
  ' Die abgefragten Daten anzeigen
  With cl.Eigenschaft
    MsgBox "Abgefragte Daten: " + vbCrLf + _
     .s + vbCrLf + CStr(.d) + vbCrLf + CStr(.v) + _
     vbCrLf + CStr(.z) + vbCrLf + CStr(.st.s) + vbCrLf + .comment
  End With
 
  ' Ereignismeldung im Klassenmodul auslösen
  cl.Melde
 
  ' Objekt wieder zerstören
  Set cl = Nothing      
End Sub
 
' Codeende - Formular Form1
' --------------------------------------------------------

Code für Modul "Module1"

' -------------------------------------------------
' Code bitte in Standardmodul Module1 einfügen
 
Option Explicit
 
' in MyType enthaltener Untertyp
' (muss vor MyType deklariert werden)
Public Type MySubTyp
  s As String
  d As Double
  v As Variant
  z As Date
  comment As String
End Type
 
' öffentlicher Demo-Datentyp in Standardmodul
' Elemente bestehen aus diversen Datentypen
Public Type MyTyp
  s As String
  d As Double
  v As Variant
  z As Date
  comment As String
  st As MySubTyp
End Type
 
' Codeende - Standardmodul Module1
' --------------------------------------------------------

Code für das Klassenmodul "Class1"

' --------------------------------------------------------
' Code bitte einfügen in Klassenmodul Class1
Option Explicit
 
' Variablen zur Speicherung der Daten der Eigenschaft
 
' Variable zum Speichern des Inhalts eines Datentyps
' (Friend geht hier nicht, aber der
' öffentliche Datentyp steht zur Verfügung !!)
Private gt As MyTyp
 
' Ereignis definieren ('Friend' nicht möglich)
Public Event Meldung(ByVal pointer As Long)
Friend Property Let Eigenschaft(ByRef t As MyTyp)
  ' Eigenschaft akzeptiert eine UDT, die an ein
  ' Klassenmodul übergeben wird
 
  ' Auslesen der Daten aus der übergebenen Datentyp-Variable
  ' und Speichern in der klasseninternen Datentyp-Variable
  gt = t
 
  ' Die folgende Zuweisung wird in LET_Property nicht zurückgegeben !!
  ' (byref wird ignoriert !)
  t.comment = "Ich war in Class1 / Eigenschaft LET"
End Property
Friend Property Get Eigenschaft() As MyTyp
  ' Abfrage der gespeicherten Daten
  ' aus der modulglobalen Variable
  Eigenschaft = gt
  Eigenschaft.comment = "Daten aus Class1 / abgefragt durch Eigenschaft GET"
End Property
Public Function Melde()
  ' Die Funktion löst das Ereignis 'Meldung' aus
  ' Die Meldung liefert nur einen Zeiger auf die internen Daten
  RaiseEvent Meldung(VarPtr(gt))
End Function
 
' Codeende - Klassenmodul Class1
' --------------------------------------------------------

Dieser Tipp wurde bereits 14.766 mal aufgerufen.

Voriger Tipp   |   Zufälliger Tipp   |   Nächster Tipp

Über diesen Tipp im Forum diskutieren
Haben Sie Fragen oder Anregungen zu diesem Tipp, können Sie gerne mit anderen darüber in unserem Forum diskutieren.

Neue Diskussion eröffnen

nach obenzurück


Anzeige

Kauftipp Unser Dauerbrenner!Diesen und auch alle anderen Tipps & Tricks finden Sie auch auf unserer aktuellen vb@rchiv  Vol.6

Ein absolutes Muss - Geballtes Wissen aus mehr als 8 Jahren vb@rchiv!
- nahezu alle Tipps & Tricks und Workshops mit Beispielprojekten
- Symbol-Galerie mit mehr als 3.200 Icons im modernen Look
Weitere Infos - 4 Entwickler-Vollversionen (u.a. sevFTP für .NET), Online-Update-Funktion u.v.m.
 
   

Druckansicht Druckansicht Copyright ©2000-2024 vb@rchiv Dieter Otter
Alle Rechte vorbehalten.
Microsoft, Windows und Visual Basic sind entweder eingetragene Marken oder Marken der Microsoft Corporation in den USA und/oder anderen Ländern. Weitere auf dieser Homepage aufgeführten Produkt- und Firmennamen können geschützte Marken ihrer jeweiligen Inhaber sein.

Diese Seiten wurden optimiert für eine Bildschirmauflösung von mind. 1280x1024 Pixel