Galileo Computing < openbook >
Galileo Computing - Bücher zur Programmierung und Softwareentwicklung
Galileo Computing - Bücher zur Programmierung und Softwareentwicklung

...powered by haas.homelinux.net...

Einstieg in VB.NET von René Martin
- Für Programmiereinsteiger -
Einstieg in VB.NET
gp Kapitel 7 Eigene Objekte
  gp 7.1 Objekte
  gp 7.2 Eine eigene Klasse
    gp 7.2.1 Members
    gp 7.2.2 Eigenschaften
    gp 7.2.3 Methoden
    gp 7.2.4 Konstruktoren
    gp 7.2.5 Überladen
    gp 7.2.6 Vererbung
    gp 7.2.7 Überschreiben
    gp 7.2.8 Polymorphismus


Galileo Computing

7.2 Eine eigene Klasse  downtop

Auf dem Startformular befindet sich ein Button, der den Namen »butEis« trägt und die Beschriftung »Eismaschine«. Mit seiner Hilfe soll Speiseeis erzeugt werden (siehe Abbildung 7.1).

Abbildung

Abbildung 7.1   Das neue Formular

Im Projektmappen-Explorer kann über das Kontextmenü Hinzufügen Klasse hinzufügen (oder das Menü Projekt Klasse hinzufügen) eine neue Klasse eingefügt werden. Sie wird unter dem Namen »clsSpeiseeis« gespeichert und steht daraufhin im Projektmappen-Explorer. Sie besteht bereits aus den beiden Zeilen

Public Class clsSpeiseeis

End Class
Abbildung

Abbildung 7.2   Die neue Klasse

Das Schlüsselwort Public ist verständlich, da schließlich von einer anderen Klasse, das heißt von unserem Formular, diese Klasse aufgerufen werden soll.

Abbildung

Abbildung 7.3   Der Code


Galileo Computing

7.2.1 Memberdowntop

Die einfachste Möglichkeit, eine Eigenschaft festzulegen, besteht darin, in die Klasse die Zeile

Public Kugelpreis as Decimal

einzufügen. Nun kann im Formular schon damit gearbeitet werden. Zuerst wird es instanziert, das heißt deklariert. Da beim Laden des Formulars die Eigenschaft festgelegt wird und da möglicherweise das Objekt mehreren Steuerelementen zur Verfügung stehen muss, wird es global, das heißt für das gesamte Formular deklariert. Also befindet sich am Anfang des Codes hinter

Public Class frmStart
Inherits System.Windows.Forms.Form

die Zeile:

Dim Speiseeis As New clsSpeiseeis()

Ganz genau könnte man sogar schreiben:

Private Dim Speiseeis As New clsSpeiseeis()

oder natürlich:

Private Dim Speiseeis As clsSpeiseeis()
Speiseeis = New clsSpeiseeis()
Abbildung

Abbildung 7.4   Das neue Objekt erscheint in der Liste.

Und nun kann im Ereignis Load, also in

Private Sub Form1_Load(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles MyBase.Load

End Load

eingefügt werden:

Speiseeis.Kugelpreis = 1.2
Abbildung

Abbildung 7.5   Das Objekt erhält eine Methode.

Nach der Eingabe des Punkts hinter »Speiseeis« erscheint nicht nur die Eigenschaft »Preis«, sondern auch die Methode »GetType«. Sie steht in jeder Klasse zur Verfügung. Achten Sie darauf, dass die Dezimalzahl im Code mit einem Punkt und nicht mit einem Komma geschrieben wird!

Die Ausgabe erfolgt hinter dem Button »butEis«:

Private Sub butEis_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs)
   MessageBox.Show("Das Eis kostet: " & _
   Speiseeis.Kugelpreis)
End Sub

Bis hierher haben wir eine einfache Eigenschaft »Preis« unseres Objekts »Speiseeis« erstellt. Es muss Public deklariert werden, damit es von »außen« verwendet werden kann. Diese Eigenschaft kann nun gesetzt und abgefragt werden.


Galileo Computing

7.2.2 Eigenschaften  downtop

Doch solche Eigenschaften können auch komplexer aufgebaut werden. In unserer Klasse wird eine zweite Variable deklariert, die allerdings nur innerhalb der Klasse verwendet wird:

Private m_Sorte As String

Werden die Sorten nur gelesen, so wird eine Eigenschaft installiert:

ReadOnly Property Sorte() As String
   Get
      Return m_Sorte
   End Get
End Property

Nun muss die Eissorte noch gefüllt werden. Dies übernimmt eine Methode, die sich hinter End Property befindet:

Public Sub EisFüllen()
   m_Sorte = "Schokolade"
End Sub

Das bedeutet, dass zuerst die Methode aufgerufen werden muss und danach die Eigenschaft abgefragt werden kann:

Private Sub butEis_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs)
   Speiseeis.EisFüllen
   MessageBox.Show("Die heutige Eisgeschmacksrichtung: " _
   & Speiseeis.Sorte)
End Sub
Abbildung

Abbildung 7.6   Über eine Methode wird eine Eigenschaft festgelegt.

Eigenschaften müssen jedoch nicht schreibgeschützt sein, man kann sie auch änderbar zur Verfügung stellen. Angenommen, der gesamte Preis darf 10 Euro nicht überschreiten. Dann kann der Endpreis gesetzt und abgefragt werden:

Private m_Endpreis As Decimal = 1.2
Property Endpreis() As Decimal
   Get
      Return m_Endpreis
   End Get
   Set(ByVal Value As Decimal)
      If Value >=10 Then
         m_Endpreis = 10
      Else
         m_Endpreis = Value
      End If
   End Set
End Property

Die private Variable m_Endpreis ist nötig, da der Endpreis sowohl gesetzt (Set) als auch gelesen wird (Get). Der Wert, den der Benutzer eingibt, wird über die Variable Value übergeben und kann dann weiterverarbeitet werden. Nun kann eine Eigenschaft natürlich Werte einer anderen Eigenschaft weiterverarbeiten. Wer am Anfang Schwierigkeiten mit den beiden Schlüsselwörtern Get und Set hat, der muss lediglich auf die Klammer achten, in der ein Parameter übergeben wird: Set erhält einen Wert, das heißt bei Set wird die Eigenschaft gesetzt, Get erhält keinen, gibt folglich einen Wert zurück, also ist Get für das Lesen der Eigenschaft verantwortlich.

Im folgenden Beispiel wird die Kugelzahl festgelegt und der Endpreis definiert. Daraus berechnet sich der Endpreis neu. Es werden deklariert:

Public Kugelzahl As Byte
Private m_Endpreis as Decimal = 1.2
Property Endpreis() As Decimal
   Get
      If Kugelzahl > 10 Then
         Kugelzahl = 10
      End If
      If Kugelpreis * Kugelzahl < 12 Then
         m_Endpreis = Kugelpreis * Kugelzahl
      Else
         m_Endpreis = 12
      End If
      Return m_Endpreis
   End Get
   Set(ByVal Value As Decimal)
      m_Endpreis = Value
   End Set
End Property
...
End Class

Wird nun die Kugelzahl auf 20 festgelegt und der Kugelpreis auf 1 Euro, so liefert

MessageBox.Show("Das Speiseeis kostet: " & _
Speiseeis.Endpreis.ToString("C")

10, weil die Kugelzahl auf 10 reduziert wird – und damit auch die Eigenschaft Endpreis. Bei 5 Kugeln und einem Preis von 1,50 Euro wird korrekt 7,50 Euro für das Speiseeis berechnet.

Abbildung

Abbildung 7.7   Kugeln à 1,00 Euro


Galileo Computing

7.2.3 Methoden  downtop

Werden Parameter übergeben, die dann weiterverarbeitet werden, so sollten Sie eine Funktion verwenden:

Function Zuschlag(ByVal Größe As String) As Decimal
   Dim decZuschlag As Decimal
   Select Case Größe
      Case "klein"
         decZuschlag = 0
      Case "mittel"
         decZuschlag = 0.5
      Case "groß"
         decZuschlag = 1
      Case Else
         decZuschlag = 0
      End Select
   Return decZuschlag
End Function

Diese Funktion wird beispielsweise aufgerufen über:

MessageBox.Show("Zuschlag: " & _
Speiseeis.Zuschlag("mittel").ToString("C")
Abbildung

Abbildung 7.8   Eine Methode erhält einen Wert, verarbeitet ihn und gibt einen Wert zurück.

Wird eine Prozedur eingebaut, so fungiert sie als Methode. In der Klasse befindet sich:

Sub Aufforderung()
   MessageBox.Show("Bitte zahlen Sie das Eis!")
End Sub

Diese Prozedur wird aktiviert durch:

Speiseeis.Aufforderung()

Sicherlich ist Ihnen in VB.NET schon aufgefallen, dass keine klare Trennung zwischen den unterschiedlichen Methoden vorliegt. Mit dem Erzeugen eigener Methoden wird deutlich, warum dies so ist:

Eine Methode »tut« in der Regel etwas (so wie im obigen Beispiel die Prozedur »Aufforderung«). Die Methode könnte aber auch einen Wert zurückgeben. Beispielsweise so:

Sub Aufforderung() As String
   Return "Bitte zahlen Sie das Eis!"
End Sub

Die Prozedur könnte auch einen Wert erhalten:

Sub Aufforderung(Text As String) As String
   Return "Bitte zahlen Sie das " & Text
End Sub

Damit wird die Prozedur zu einer Funktion: Sie erhält einen Wert und gibt einen zurück. Analog könnte man auch schreiben:

Function Aufforderung(Text As String) As String
   Return "Bitte zahlen Sie das " & Text
End Function

In der Praxis gibt es keinen Unterschied zwischen einer Funktion und einer Prozedur: Beide können entweder keinen, einen Parameter oder mehrere Parameter entgegennehmen. Beide können etwas ausführen und können (müssen aber nicht) einen Wert zurückgeben. Ich persönlich versuche, zwischen Prozeduren und Funktionen zu trennen (damit ich später noch weiß, was ich getan habe). Bei mir geben Funktionen immer einen Wert zurück, Prozeduren nie. Aber das ist auch schon der einzige Unterschied. Man könnte es auch anders machen.

Wenn Sie in VB.NET eine Methode sehen und nicht wissen, wie sie korrekt verarbeitet wird, dann geben Sie nach der Methode eine Klammer ein: Denn jede Methode verlangt eine Klammer. Wird nach einem Parameter gefragt, dann muss er eingegeben werden. Gibt die Methode einen Wert zurück, so ist der Typ hinter der schließenden Klammer mit einem As gekennzeichnet.


Galileo Computing

7.2.4 Konstruktoren  downtop

Zu Beginn des Kapitels haben wir den Member »Kugelpreis« festgelegt, der als Eigenschaft fungiert. Angenommen, eine Klasse wird instanziert und eine Eigenschaft oder ein Member soll nun schon einen Vorgabewert besitzen. Dann kann dies mit dem Schlüsselwort New in einer Klasse festgelegt werden:

Public Sub New()
   Kugelpreis = 1
   m_Sorte = "Erdbeere”
End Sub

Das Schlüsselwort New ist bekannt: Wird eine Klasse das erste Mal verwendet, dann wird sie mit New aufgerufen. Manche Klassen besitzen allerdings verschiedene Varianten, zwischen denen der Benutzer mit der Pfeiltaste oder der Maus wechseln kann. Soll nicht nur eine Prozedur »New« zur Verfügung gestellt werden, sondern mehrere, dann wird es wie folgt realisiert:

Public Sub New(ByVal Tagessorte As String)
   Kugelpreis = 1
   m_Sorte = Tagessorte
End Sub

Galileo Computing

7.2.5 Überladen  downtop

Problemlos können mehrere Prozeduren koexistieren, wenn sie unterschiedliche Parameter besitzen. Startet der Benutzer nun seine Klasse mit

Private Dim Speiseeis As New clsSpeiseeis()

oder mit:

Private Dim Speiseeis As clsSpeiseeis()
Speiseeis = New clsSpeiseeis()

so wird er nach Eingabe der öffnenden Klammer gefragt, welche der beiden Varianten er bevorzugt. Einen solchen Konstruktor nennt man »überladen«.

Abbildung

Abbildung 7.9   Überladene Konstruktoren sind bekannt, beispielsweise vn MessageBox.Show.

Ebenso können Methoden überladen werden. Neben einer Funktion, welche die Mehrwertsteuer mit 16  % berechnet, soll eine zweite Funktion implementiert werden, die eine variable Mehrwertsteuer zulässt:

Public Function MWSt() As Decimal
   Return Preis / 1.16 * 0.16
End Function

Die zweite Funktion trägt den gleichen Namen, allerdings verlangt sie einen Parameter:

Public Function MWSt(MWStSatz As Decimal) As Decimal
Return Preis / (1 + MWStSatz) * MWStSatz
End Function

Damit wird die Methode auf zweierlei Arten angezeigt, wenn sie an anderer Stelle verwendet wird.

Abbildung

Abbildung 7.10   Eine überladene Methode


Galileo Computing

7.2.6 Vererbung  downtop

Interessant wird das Klassenkonzept einer objektorientierten Programmiersprache, wenn Vererbung ins Spiel kommt. Das bedeutet, dass eine zweite Klasse erstellt werden kann: Hinzufügen Klasse. Sie erhält den Namen »clsEisbecher«. Damit sie die Methoden und Eigenschaften der ersten Klasse vererbt bekommt, wird nach

Public Class clsEisbecher

die folgende Zeile eingefügt:

Inherits clsSpeiseeis

Sämtliche Methoden und Eigenschaften stehen nun zur Verfügung, wenn wie folgt deklariert wird:

Dim eisbecher As clsEisbecher
eisbecher = New clsEisbecher()
With eisbecher
   Messagebox.Show("Die Kugel kostet immer noch: " & _
   .Preis.ToString("C"))
End With
Abbildung

Abbildung 7.11   Die Eigenschaft »Kugelpreis« wurde vererbt.

Natürlich können in der Klasse clsEisbecher eigene Eigenschaften und Methoden implantiert werden:

Private m_Alkohol As Boolean
Property Alkohol() As Boolean
   Get
      Return m_Alkohol
   End Get
   Set(ByVal Value As Boolean)
      m_Alkohol = Value
   End Set
End Property

Diese Eigenschaft steht nur der Klasse clsEisbecher zur Verfügung, nicht der Klasse clsSpeiseeis.


Galileo Computing

7.2.7 Überschreiben  downtop

Und was macht man, wenn man eine Methode oder Eigenschaft gleichen Namens in zwei Klassen benötigt, die aber jeweils unterschiedlich arbeiten soll? Angenommen, die Klasse clsSpeiseeis besitzt folgende Funktion:

Function Aufforderung2(Text As String) As String
   Return "Bitte zahlen Sie das " & Text
End Function

Wird diese Klasse nach clsEisbecher vererbt, so darf dort nicht stehen:

Function Aufforderung2(Text As String) As String
   Return "Bitte zahlen Sie sofort das " & Text
End Function
Abbildung

Abbildung 7.12   So geht das nicht!

Dies würde zu einem Fehler führen, der angezeigt wird. Damit dies dennoch ermöglicht wird, muss die Funktion in der Klasse clsSpeiseeis als überschreibbar gekennzeichnet werden. Das Schlüsselwort lautet Overridable:

Overridable Function Aufforderung2(Text As String) _
As String
   Return "Bitte zahlen Sie das " & Text
End Function

Auf der anderen Seite – in der Klasse clsEisbecher – wird das Schlüsselwort Overrides verwendet:

Overrides Function Aufforderung(Text As String) As String
   Return "Bitte zahlen Sie sofort das " & Text
End Function

Und damit sind in zwei voneinander abgeleiteten Klassen zwei Methoden implementiert, die unterschiedliche Dinge tun.

Abbildung

Abbildung 7.13   Aufforderung2a

Abbildung

Abbildung 7.14   Aufforderung2b


Galileo Computing

7.2.8 Polymorphismus  toptop

Der letzte und vielleicht entsetzlichste Begriff aus der Welt der Objektorientierung lautet »Polymorphismus«. Damit ist folgendes Konzept gemeint:

Eine Funktion ZeigeSorte verwendet die Klasse clsSpeiseeis:

Function ZeigeSorte(ByVal Eis As clsSpeiseeis) As String
   Return Eis.Sorte
End Function

Diese Funktion erhält einen Wert vom Typ clsSpeiseeis, der an die Variable Eis übergeben wird. Diese wird weiterverarbeitet. Sie wird beispielsweise folgendermaßen aufgerufen:

Dim speiseeis As clsSpeiseeis
speiseeis = New clsSpeiseeis()
Messagebox.Show(ZeigeSorte(speiseeis))

Erstaunlicherweise kann auch ein anderer Typ verwendet werden:

Dim eisbecher As clsEisbecher
eisbecher = New Eisbecher()
Messagebox.Show(ZeigeSorte(eisbecher))

Nun wird die Klasse eisbecher vom Typ clsEisbecher übergeben. Da sie von der Klasse clsSpeiseeis abgeleitet ist, funktioniert dies.

  

VB.NET

Einstieg in ASP.NET

Einstieg in C#

Visual C#

VB.NET und Datenbanken

Einstieg in XML