Eine Grundlegende Frage zur Polymorphie.

  • VB.NET

Es gibt 6 Antworten in diesem Thema. Der letzte Beitrag () ist von RodFromGermany.

    Eine Grundlegende Frage zur Polymorphie.

    Hallo!

    Ich habe nochmal eine Frage zur Polymorphie.

    Es geht um die Änderung von (bspw.)

    VB.NET-Quellcode

    1. Dim Klasse2 as New BasisKlasse(2)


    in

    VB.NET-Quellcode

    1. Dim klasse2 as ErsteKlasse
    2. klasse2 = New ZweiteKlasse(5)


    Im Entwicklerbuch Visual Basic 2010 steht dazu (S. 390): "Glauben sie, dass VB einen Fehler auslöst, da sie klasse2 als ErsteKlasse deklariert, dieser Objektvariablen anschließend aber eine Instanz von zweiter Klasse zugewiesen haben? Mitnichten! Diese Vorgehensweise ist nicht nur kein Fehler, Sie haben gerade sogar das wohl mächtigste Werkzeug der objektorientierten Programmierung kennen gelernt"(Anm.d.R.: Die Polymorphie).

    Ich habe mir ein kleines Beispiel zusammengestellt:

    VB.NET-Quellcode

    1. Module Module1
    2. Sub Main()
    3. Dim player As New ZweiteKlasse
    4. System.Console.WriteLine()
    5. player.Play()
    6. Dim klasse1 As New ErsteKlasse
    7. System.Console.WriteLine()
    8. klasse1.Play()
    9. 'Dim klasse2 as ZweiteKlasse
    10. Dim klasse2 As ErsteKlasse
    11. klasse2 = New ZweiteKlasse
    12. System.Console.WriteLine()
    13. klasse2.Play()
    14. System.Console.WriteLine()
    15. System.Console.ReadLine()
    16. End Sub
    17. Class ErsteKlasse 'base Class
    18. Private strName As String 'strName as a private member
    19. Public intAge As Integer 'intAge as a public member
    20. Public Function getName()
    21. Return strName
    22. End Function
    23. Public Sub SetName(ByVal name As String)
    24. strName = name
    25. End Sub
    26. Public Overridable Sub Play()
    27. System.Console.WriteLine("I Play Nothing")
    28. End Sub
    29. End Class
    30. Class ZweiteKlasse 'derived Class
    31. Inherits ErsteKlasse
    32. Public strNationality As String 'derived classes member
    33. Function getNationality()
    34. Return strNationality
    35. End Function
    36. Public Overrides Sub Play()
    37. System.Console.WriteLine("I can Play cricket")
    38. End Sub
    39. End Class
    40. End Module


    Das Ergebnis ändert sich nicht, wenn man die Kommentierung hier:

    VB.NET-Quellcode

    1. 'Dim klasse2 as ZweiteKlasse
    2. Dim klasse2 As ErsteKlasse

    tauscht.

    Was ich verstehe ist, dass ich beim Deklarieren einer Objektvariable die Elternklasse verwenden kann und dann beim Instanzieren dieser Objektvarialben eine Instanz einer Kindsklasser der Elternklasse zuweisen kann. OK, aber was bringt mir das? Insbesondere, wie man am o.g. Beispiel sieht, da kommt ja eh das gleiche raus, ob ich jetzt die die Objektvariable als Eltern- oder Kindsklasse deklariere.

    Wäre super, wenn mir das jemand erklären könnten, da es ja anscheinend eines der "wichtigesten Tools der OOP" ist, welches bei mir noch in der mit sieben Siegeln verschlossenen Toolbox verweilt. Auf das Klick-Event wartend...
    Ruedi
    Ich vergleiche es mal mit den Interfaces:

    VB.NET-Quellcode

    1. Dim Disposer As IDisposable
    2. Disposer = New Stream 'Implementiert glaub' ich IDisposable
    3. Disposer.dispose

    Du deklarierst eine leere Schnittstelle, die du dann mit einer Instanz, die IDisposable implementiert gefüllt wird.
    In diesem Beispiel bringt dir das tatsächlich nicht wirklich was.
    Hier hast du ein besseres Beispiel (ist sogar mit einigen äußerst wichtigen Framework-Klassen):

    VB.NET-Quellcode

    1. Public Function ReadTenBytes(stream As Stream) As Byte()
    2. Dim buffer As New Byte(9) {}
    3. stream.Read(buffer, 0, 10)
    4. Return buffer
    5. End Function
    Der Sinn hinter dieser Funktion sei mal außenvor gelassen. Es werden einfach 10 Bytes aus einem Stream ausgelesen.
    Aber jetzt wirds interessant. Die drei wichtigsten Stream-Klassen im Framework sind wohl FileStream, NetworkStream und MemoryStream. Der FileStream bezieht seine Ressourcen aus einer Datei, der MemoryStream aus dem RAM und der NetworkStream aus einem Netzwerk (z.B. aus dem Internet). Welchen dieser Streams du der Funktion übergibst, spielt keine Rolle, denn die Funktion interssiert sich nur dafür, dass sie irgend einen Stream bekommt, aus dem sie lesen kann. Wie dieser Lesevorgang von statten geht (also ob aus einer Datei, dem RAM oder einer Netzwerressource gelesen wird) ist der Funktion egal.
    Polymorphie wird also immer dann nützlich, wenn du den genauen Typen eines Objektes nicht kennst, sondern nur seinen Basistypen oder ein Interface, welches er implementiert. Und sowas kommt ziemlich oft vor, wenn man anfängt abstraktere und größere Strukturen auszuarbeiten. Tatsächlich ist es der Inbegriff der Abstraktion, Probleme immer auf der kleinst möglichen Basisklasse/Interface zu lösen, da man so eben mehr Spielraum hat. Bevor man sowas nutzen kann, muss man natürlich erstmal lernen, wie man überhaupt Probleme auf ein Minimum reduziert und sinnvolle Basisklassen/Interfaces anlegt.
    Nehmen wir mal an, du hättest eine (häufig abstrakte) Oberklasse "Fahrzeug" und entsprechende Unterklassen wie "Auto", "Motorrad" und "Boot". Der große Vorteil ist nun, dass du alle Unterklassen über die (oft schmalere) Schnittstelle der Oberklasse ansteuern kannst. Du musst nicht wissen, welche Unterklasse sich hinter dem Fahrzeug verbirgt aber du kannst sowohl Boot als auch Auto mit dem gleichem Code ansteuern.

    Sowas macht man übrigens andauernd: Die Me.Controls-Auflistung beinhaltet Controls (eine Oberklasse). Eine Methode von Control ist OnPaint - diese überschreiben die meisten Controls um sich anders darstellen zu können. Um die GUI anzuzeigen wird nun die Controls-Auflistung durchlaufen und currentControl.OnPaint(...) aufgerufen. Egal ob das nun eine Listbox, Picturebox, Label, Checkbox, etc ist (der genaue Typ ist egal) - die passende OnPaint-Methode wird automatisch aufgerufen.

    Also weitere wichtige Schlagwörter wären Vererbung, Interfaces und Abstrakte Klassen. Vererbung stellt eine Ist-Beziehung dar (ein Auto IST ein Fahrzeug, aber ein Fahrzeug muss nicht ein Auto sein, sondern kann auch eine Mondrakete sein). Interfaces sind Verträge in denen festgelegt wird, welche Methoden/Eigenschaften/Events eine Klasse haben muss. Abstrakte Klassen sind ähnlich wie Interfaces, nur dass man hier schon Code einbauen kann, aber andere Methoden/etc von der Unterklasse implementiert werden müssen.

    Das geht eigentlich alles Hand in Hand, also schön am Ball bleiben^^

    ruediger_006 schrieb:

    VB.NET-Quellcode

    1. Module Module1
    Wenn Du richtig objektorientiert programmieren willst, vergiss, dass es Module gibt. Diese haben in VB nur noch für Befehlserweiterungen eine Daseinsberechtigung.
    Klassen in ein Modul hineinzuschreiben sind ein NoGo!
    Üblicherweise kommt jede Klasse in eine separate Datei. Wenn Du Daten für das gesamte Programm halten willst, mach Dir eine Datenklasse mit Shared Variablen.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!