Overrides und Overridable

  • VB.NET

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

    Overrides und Overridable

    So, ich bins mal wieder mit einer Frage^^

    Hab mir jetzt ein paar Sachen angeguckt wofür man Prozeduren mit Overrides und Overridable betitelt.
    Nun versteh ich den Sinn dahinter nicht. Sofern ich das nicht falsch verstanden habe ist das dazu da:

    Es gibt zwei Funktionen, welche in verschiedenen Klassen sind. Wenn diese jetzt den gleichen Namen haben (z.B. Function Test()), stellt man vor einem ein Overrides und bei dem anderen ein Overridable dran. Jetzt werden die Funktionen "gefiltert" also, der Computer weiß welche Funktion in welcher Klasse gemeint ist.
    Aber man kann doch dann genauso gut einfach den Namen einer Funktion ändern und das wars?

    Vermutlich hab ich den Sinn dahinter nur nicht verstanden ^^
    Wäre aber trotzdem schön wenn ihn mir einer erklären könnte..

    Habe auch ein Beispiel versucht für alle die nicht verstehen was ich damit sagen will:

    VB.NET-Quellcode

    1. Public Class Form1
    2. Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
    3. Function2()
    4. End Sub
    5. Overridable Function Function2() As DialogResult
    6. Return MessageBox.Show("erste Klasse")
    7. End Function
    8. End Class
    9. Public Class Test
    10. Inherits Form1
    11. Overrides Function Function2() As DialogResult
    12. Return MessageBox.Show("zweite Klasse")
    13. End Function
    14. End Class


    aber ich könnte doch auch genausogut es so machen:

    VB.NET-Quellcode

    1. Public Class Form1
    2. Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
    3. Function2()
    4. End Sub
    5. Function Function2() As DialogResult
    6. Return MessageBox.Show("erste Klasse")
    7. End Function
    8. End Class
    9. Public Class Test
    10. Inherits Form1
    11. Function Function3() As DialogResult
    12. Return MessageBox.Show("zweite Klasse")
    13. End Function
    14. End Class
    Das ist der zusammen mit "MustOverride" ein Großteil dessen, was die Polymorphie ausmacht.
    Es gibt im Framework eine Klasse "Stream", die zum Lesen und Schreiben von Daten aus beliebigen Orten gedacht ist. Das bedeutet, jeder Stream besitzt eine Read und eine Write-Methode. Nun gibt es aber unterschiedlichste Arten von Streams, wie z.B. Memorystream, Filestream oder Networkstrem. Jeder dieser Streams funktioniert anders und muss daher auch anders lesen und schreiben. Der Memorystream Liest und Schreibt im dem Arbeitsspeicher, der Filestream Liest und schreibt auf der Festplatte und der Networkstream läd Daten hoch und runter. Es sind aber trotzdem alles Streams, mit denen man Lesen und Schreiben kann. Es ist z.B. möglich, eine Bitmap aus einem Stream zu erzeugen. Dafür ist es dann völlig unerheblich, ob die nun ein Memorystream, ein Filestream oder ein Networkstream ist, denn wie die Daten herangeschafft werden interessiert die Bitmap nicht, sie liest lediglich aus dem Stream.
    In etwa sieht das so aus:

    VB.NET-Quellcode

    1. Public MustInherit Class Stream
    2. Public MustOverride Function Read (<OutAttribute> buffer As Byte(), offset As Integer, count As Integer) As Integer
    3. End Class
    4. Public Class MemoryStream : Inherits Stream
    5. Public Overrides Function Read (<OutAttribute> buffer As Byte(), offset As Integer, count As Integer) As Integer
    6. 'aus dem RAM lesen
    7. End Sub
    8. End Class
    9. Public Class FileStream : Inherits Stream
    10. Public Overrides Function Read (<OutAttribute> buffer As Byte(), offset As Integer, count As Integer) As Integer
    11. 'von der Festplatte lesen
    12. End Sub
    13. End Class
    14. Public Class NetworkStream : Inherits Stream
    15. Public Overrides Function Read (<OutAttribute> buffer As Byte(), offset As Integer, count As Integer) As Integer
    16. 'etwas downloaden
    17. End Sub
    18. End Class

    Und wenn du dann eine Variable vom Typ Stream hast, dann kann da jeder mögliche Stream drin sein, aber du kannst definitiv daraus lesen. Ob dann im Hintergrund die Daten aus dem RAM, von der Festplatte, oder aus dem Internet kommen, macht keinen Unterschied.
    Ja, aber ginge dann auch nicht das:

    VB.NET-Quellcode

    1. Public Class Stream
    2. Public Function Read1(<OutAttribute()> buffer As Byte(), offset As Integer, count As Integer) As Integer
    3. End Function
    4. End Class
    5. Public Class MemoryStream
    6. Public Function Read2(<OutAttribute()> buffer As Byte(), offset As Integer, count As Integer) As Integer
    7. 'aus dem RAM lesen
    8. End Function
    9. End Class
    10. Public Class FileStream
    11. Public Function Read3(<OutAttribute()> buffer As Byte(), offset As Integer, count As Integer) As Integer
    12. 'von der Festplatte lesen
    13. End Function
    14. End Class
    15. Public Class NetworkStream
    16. Public Function Read4(<OutAttribute()> buffer As Byte(), offset As Integer, count As Integer) As Integer
    17. 'etwas downloaden
    18. End Function
    19. End Class


    Dann würde zwar die Zahl noch hintendran stehen (was unschön aussieht) aber es würde funktionieren?
    Aber du könntest nicht sowas hier machen:

    VB.NET-Quellcode

    1. Public Function UseStream(ByVal stream As Stream)
    2. Dim buffer As Byte()
    3. stream.Read(buffer, 0, 10) 'liest die ersten 10 Bytes aus dem Stream
    4. 'hier wird irgendwas mit diesen Bytes gemacht
    5. End Function
    6. Public Function Test()
    7. Dim memoryStream As MemoryStream
    8. Dim fileStream As FileStream
    9. Dim networkStream As NetworkStream
    10. 'hier die Streams initialisieren
    11. UseStream(memoryStream)
    12. UseStream(fileStream)
    13. UseStream(networkStream)
    14. End Function
    Wenn man statt Stream, Filestream / Memorystream oder Networkstream da eintragen würde?
    Ich mach jetzt nur Vermutung, weiß nicht obs funktioniert, wirst du wahrscheinlich eher wissen.


    VB.NET-Quellcode

    1. Public Function UseStream(ByVal stream As Filestream / Memorystream / Networkstream) '
    2. Dim buffer As Byte()
    3. Stream.Read(buffer, 0, 10) 'liest die ersten 10 Bytes aus dem Stream
    4. 'hier wird irgendwas mit diesen Bytes gemacht
    5. End Function
    6. Public Function Test()
    7. Dim memoryStream As MemoryStream
    8. Dim fileStream As FileStream
    9. Dim networkStream As NetworkStream
    10. 'hier die Streams initialisieren
    11. UseStream(memoryStream)
    12. UseStream(fileStream)
    13. UseStream(networkStream)
    14. End Function
    Mal abgesehen davon dass es unschön aussieht, wenn du dann fein von Stream erbst haste auf einmal 2 Methoden. Du kannst übrigens auch die zuüberschreibende Methode immernoch ausser Überschreibenden aufrufen, nicht aufs Beispiel bezogen.
    /
    Du könntest daraus natürlich ne template Funktion machen und prüfen obs von Stream erbt, trotzdem haste noch dein Read1,2,3
    Das geht natürlich, aber eben genau sowas ist aller größter Ranzcode vom feinsten. Dann musst du nämlich drei verschiedene Methoden schreiben, die vom Inhalt her fast identisch sind.
    Der Trick bei der Sache ist eben, dass die Methode gar nicht weiß, was für eine Art von Stream sie bekommt. Das ist aber auch nicht weiter schlimm, denn das muss sie auch nicht wissen. Sie weiß nur, dass irgendein Stream kommt und aus einem Stream kann gelesen werden.
    Hi
    hier noch ein paar Beispiele, die mir dazu so eingefallen sind:

    VB.NET-Quellcode

    1. Public Class Player
    2. Private _health As Integer
    3. Public Property Health As Integer
    4. Get
    5. Return _health
    6. End Get
    7. Set(value As Integer)
    8. If value < 0 Then Throw New ArgumentOutOfRangeException("Health", "Non-negative health expected.")
    9. Dim previous As Integer = Health
    10. value = ValidateHealth(value)
    11. _health = value
    12. OnHealthChanged(previous)
    13. If value = 0 Then
    14. OnPlayerDead()
    15. End If
    16. End Set
    17. End Property
    18. Public Property MaxHealth As Integer
    19. Public Sub ModHealth(amount As Integer)
    20. Health = Math.Min(Math.Max(Health + amount, 0), Math.Max(Health, MaxHealth))
    21. End Sub
    22. 'Überschreibbare Funktion, um Werte zu korrigieren
    23. Protected Overridable Function ValidateHealth(value As Integer) As Integer
    24. Return value
    25. End Function
    26. 'Überschreibbare Prozeduren, um ableitende Klassen über Änderungen zu informieren
    27. Protected Overridable Sub OnPlayerDead()
    28. End Sub
    29. Protected Overridable Sub OnHealthChanged(previous As Integer)
    30. End Sub
    31. End Class
    32. Public MustInherit Class Fruit
    33. Public MustOverride Sub Eat(player As Player)
    34. Public MustOverride ReadOnly Property Name As String
    35. 'Standardverhalten ist, dass aus Früchten keine Pflanzen wachsen können
    36. Public Overridable ReadOnly Property CanGrowNewPlant As Boolean
    37. Get
    38. Return False
    39. End Get
    40. End Property
    41. 'Somit wird auch eine Exception geworfen
    42. Public Overridable Function GrowNewPlant() As Plant
    43. Throw New NotSupportedException()
    44. End Function
    45. 'Fruit.ToString gibt jetzt für alle Früchte Name zurück. Es kann nicht mehr überschrieben werden (==> NotOverridable)
    46. Public NotOverridable Overrides Function ToString() As String
    47. Return Name
    48. End Function
    49. End Class
    50. Public Class Apple
    51. Inherits Fruit
    52. Public Overrides Sub Eat(player As Player)
    53. player.ModHealth(player.MaxHealth \ 10)
    54. End Sub
    55. 'Name ist hier bei der diskreten Klasse Apfel festgelegt als Apple, kann in Subklassen noch überschrieben werden
    56. Public Overrides ReadOnly Property Name As String
    57. Get
    58. Return "Apple"
    59. End Get
    60. End Property
    61. 'Aus Apfelkernen können Apfelbäume wachsen ==> das Verhalten wird überschrieben.
    62. ' Aus kernlosen Trauben könnten z.B. keine Pflanzen wachsen
    63. Public Overrides ReadOnly Property CanGrowNewPlant As Boolean
    64. Get
    65. Return True
    66. End Get
    67. End Property
    68. Public Overrides Function GrowNewPlant() As Plant
    69. Return New AppleTree()
    70. End Function
    71. End Class
    72. Public MustInherit Class PoisonousFruit
    73. Inherits Fruit
    74. 'Name ist abstrakt, der Spieler stirbt beim Essen einer giftigen Frucht
    75. Public Overrides Sub Eat(player As Player)
    76. player.Health = 0
    77. End Sub
    78. End Class
    79. Public MustInherit Class Plant
    80. Public MustOverride Sub SubmitTimePassed(time As TimeSpan)
    81. End Class
    82. Public Class AppleTree
    83. Inherits Plant
    84. Public Overrides Sub SubmitTimePassed(time As TimeSpan)
    85. 'neue Äpfel wachsen lassen, Baum wachsen lassen, whatever
    86. End Sub
    87. End Class


    Gruß
    ~blaze~

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „~blaze~“ ()

    Erstell Dir mal folgendes Beispiel:
    Basisklasse: EbeneGeometrie (oder so)
    abgeleitete Klassen: Kreis, Rechteck, Dreieck
    zu implementierende Funktionen: Fläche, Umfang
    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!
    Habs versucht:

    VB.NET-Quellcode

    1. Public Class Form1
    2. Private Rechteck As Geometrie = New Rechteck
    3. Private Sub Form1_Paint(sender As Object, e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint
    4. 'zeichnen
    5. End Sub
    6. End Class
    7. Public MustInherit Class Geometrie
    8. Public MustOverride Function Draw(ByVal rectangle As Rectangle, ByVal graphics As Graphics) As Rectangle
    9. End Class
    10. Public Class Kreis : Inherits Geometrie
    11. Public Overrides Function Draw(rectangle As System.Drawing.Rectangle, ByVal graphics As Graphics) As System.Drawing.Rectangle
    12. _Kreisfläche = rectangle
    13. With graphics
    14. .DrawEllipse(Pens.Black, Kreis)
    15. End With
    16. End Function
    17. Private _Kreisfläche As Rectangle
    18. Public ReadOnly Property Kreis As Rectangle
    19. Get
    20. Return _Kreisfläche
    21. End Get
    22. End Property
    23. End Class
    24. Public Class Rechteck : Inherits Geometrie
    25. Public Overrides Function Draw(rectangle As System.Drawing.Rectangle, ByVal graphics As Graphics) As System.Drawing.Rectangle
    26. _Rechtecksfläche = rectangle
    27. With graphics
    28. .DrawRectangle(Pens.Black, Rechteck)
    29. End With
    30. End Function
    31. Private _Rechtecksfläche As Rectangle
    32. Public ReadOnly Property Rechteck As Rectangle
    33. Get
    34. Return _Rechtecksfläche
    35. End Get
    36. End Property
    37. End Class


    so richtig??

    Ahja, Wie zeichnet man ein Dreieck? Gibts da nen Befehl für, oder muss man einfach nen array mit 3 Punkten nehmen und die verbinden?
    Ja das war jetzt nicht auf seinen post bezogen sondern allgemein auf das thema, ich probiers dann mal mit Fläche usw

    Damit ist aber gemeint, eine Funktion zum berechnen eines Kreis/Dreieck/Rechteck Umfangs bzw der Fläche?

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „RushDen“ ()

    RushDen schrieb:

    Habs versucht:
    Was?
    Einn Dreieck ist ein Polygon.
    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!