vb@rchiv
VB Classic
VB.NET
ADO.NET
VBA
C#
Brandneu! sevEingabe v2.0 - Das Eingabecontrol der Superlative!  
 vb@rchiv Quick-Search: Suche startenErweiterte Suche starten   RSS-Feeds  | Newsletter  | Impressum  | vb@rchiv CD Vol.6  | Shop Copyright ©2000-2015
 
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:  8.793 
ohne HomepageSystem:  Win9x, WinNT, Win2k, WinXP, Vista, Win7, Win8kein Beispielprojekt 

Summer-Special bei Tools & Components!
Gute Laune Sommer bei Tools & Components
Top Summer-Special - Sparen Sie teilweise über 100,- EUR
Alle sev-Entwicklerkomponenten und Komplettpakete jetzt bis zu 25% reduziert!
zum Beispiel:
  • Developer CD nur 455,- EUR statt 569,- EUR
  • sevDTA 2.0 nur 224,30 EUR statt 299,- EUR
  •  
  • vb@rchiv   Vol.6 nur 18,70 EUR statt 24,95 EUR
  • sevCoolbar 3.0 nur 58,70 EUR statt 69,- EUR
  • - Werbung -Und viele weitere Angebote           Aktionspreise nur für kurze Zeit gültig

    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 8.793 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-2015 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