Step 20 - OOP - Vererbungslehre

Spendenaufruf des DRK Ortsvereins Spielberg e.V.

16. April 2023

 

Hallo liebe Besucherin, hallo lieber Besucher!

In einem ganz anderen Kontext möchte ich hier nun bewerben:
Der Verein, für den ich auch einstehe, benötigt Spenden:


Bitte bei der Überweisung den Verwendungszweck beachten!

Der neuste Stand gibt es hier zu sehen!

Echte Großzügigkeit gegenüber der Zukunft besteht darin, alles in der Gegenwart zu geben. (Audrey Hepburn)

 

 

OOP - Vererbungslehre

Dieses Tutorial ist die Fortsetzung von Step 19, in dem zu Beginn die Vererbung bereits am Beispiel der Klasse TBitBtn kurz angedeutet wurde. Lass uns diesen Punkt nochmal genauer anschauen.
Was ist Vererbung?
Vererbung ist ein Phänomen, um spezialisiertere Objekte, verschiedener Art und Weise zusammenzufassen und doch um bestimmte Funktionalitäten und/oder Eigenschaften zu erweitern. Die Elternklasse beinhaltet alle Attribute (=Felder) und Methoden, welche dann auch in der vererbten Klasse verfügbar sein können, sofern sie an der dafür vorgesehenen Stelle deklariert wurden. Wenn wir wollen, dass etwas in der abgeleiteten Klasse verwendet, verändert oder sogar überschrieben werden kann, so sollte dies mindestens unter protected deklariert werden. Alles unter private deklariert wurde ist in den "Kinder"-Klassen nicht verfügbar. Auf die Felder unter private kann nachträglich nur noch durch Einfügen von sogenannten Properties schreibend und lesend zugegriffen werden. Properties werden bei der Vertiefung näher beleuchtet. Hier wollen wir erstmal in die die Vererbung einleiten. Wer mit den Begriffen private/protected aber auch public und published noch nichts anfangen kann, sollte den Theorie-Teil aus Step 19 sich vorher anschauen oder im verlinkten SocialMedia ihre oder seine Fragen stellen.
Und was hat es mit dieser Vigenére-Verschlüsselung auf sich?
Die Vigenére-Verschlüsselung ist kurz gesagt eine Erweiterung der Caesar-Verschlüsselung. Hierbei können wir mit einem Passwort die "Verschiebung" definieren. Für die weitere Theorie, was dahinter ist, darf gerne wieder die Internet-Recherche genutzt werden. Hier gibt es viele Seiten, die auf die Theorie dahinter weiter eingeht. Für uns reicht erstmal die Info, dass wir wieder Buchstaben austauschen, wie es bei Caesar der Fall war.
Um hier gleich durchstarten zu können, nutzen wir die "Copy-Paste" und kopieren einfach erstmal den ganzen Projekt-Ordner und öffnen von dort aus das Projekt. Anschließend können wir es direkt durch "Projekt speichern unter" unter einem neuen Namen abspeichern: "OOP2Beispiel".
Was wollen wir nun mit Vererbung machen?
Wie in Step 19 erstellen wir nun eine neue Unit mit dem Namen "mVigenere.pas". In dieser Unit deklarieren wir auch vergleichbar mit Step 19 den type TVigenere, mit der Ausnahme, dass wir nicht von TObject ableiten, sondern von TCaesar. Um dies machen zu können müssen wir erstmal in die uses die unit mCaesar einbinden. Das ganze sollte dann etwa so aussehen:
unit mVigenere;

interface

uses
  mCaesar;

type
  TVigenere = class(TCaesar)
  private
    { private declarations }
  protected
    { protected declarations }
  public
    { public declarations }
    
  published
    { published declarations }
  end;

implementation

end.
Den Constructor deklarieren wir genau wie in Step 19, nur mit dem Unterschied, dass dieser nun einen Parameter "password:String" bekommt:
    constructor Create(password:String);
Nun müssen wir erst noch das Feld fPassword:String im privat-Abschnitt deklarieren. Hiernach können wir es im Constructor initialisieren:
constructor TVigenere.Create(password:String);
begin
  inherited Create;
  fPassword:=password;
end;
Wie im Constructor kann mittels "inherited" die function DeCode des Elternobjektes TCaesar aufgerufen werden. Somit ist es möglich den Algorithmus der Caesar-Verschlüsselung auszuführen. Wir deklarieren zunächst drei Integer-Variablen:
IndexSource: Index des zu codierenden Strings durchgehen.
IndexPw: Index des Passwortes.
code: Verschiebung von A -> move.
Und zu guter letzt noch einen String:
coded: Codiertes Wort.
Das folgende Schaubild soll den Algorithmus der Vigenére-Verschlüsselung veranschaulichen:
 
Und hier der kommentierte Script dazu:
var
    indexOrig,           // Index des Original-Strings
    indexPw,             // Index des Passwort-Strings
    move      : Integer; // Verschiebung
    coded     : String;  // Codierter String
begin
    // Variablen initialisieren:
    indexOrig:=0;
    indexPw:=0;
    coded:='';
    while indexOrig < Length(orig) do // Während noch Buchstaben zu bearbeiten sind
    begin
        Inc(indexOrig); // nächsten Buchstaben behandeln
        Inc(indexPw);   // Passwortindex um eins erhöhen
        // Wenn Passwortindex größer als Länge des Passwortes
        if indexPw > Length(fPassword) then
            // Passwortindex auf 1 zurücksetzen
            indexPw := 1;
        // Buchstabe des Passwortes in ASCII-Zahl codieren und ord('a') abziehen
        // hierbei resuliert für z.B. fPassword[indexPW]='a'  move = 0;
        move := ord(fPassword[indexPw])-97;
        if decode then          // wenn decodiert werden soll
            move := 26-move;    // dann move umdrehen -> Rückwärts verschieben
        // Funktion der Klasse TCaesar mit aktulellem Buchstaben bei indexOrig ausführen
        coded := coded + inherited DeCode(orig[indexOrig],move);
    end;
    // codierten String zurückgeben
    result:=coded;
end;
 
Nun haben wir die mVigenere.pas fertiggestellt. Um diese nun nutzen zu können, brauchen wir einige Änderungen in der MainUnit und dem Formular. Der folgende Screenshot zeigt, wie das Edit EdPassword für die Passwort-Eingabe und die RadioButtons rbCodieren bzw. rbDecodieren zur Unterscheidung von Codierung und Decodierung eingesetzt. Andere Elemente, die wir nicht benötigen, wurden entfernt.
 
Im ButtonClick-Event wird jetzt nur noch das EVA-Prinzip angewand. Die Eingabe wird durch eine Instanz von TVigenere durch Aufruf von DeCode und rbCodieren.Checked als zweiten Parameter direkt in edAusgabe codert oder decodiert wiedergegeben. Der folgende Source-Ausschnitt zeigt diese Implementierung.
    edAusgabe.Text := vigenere.DeCode( edEingabe.Text, rbCodieren.Checked);
Der vollständige Sourcecode befindet sich auch hierfür auf GitHub. Viel Spaß damit :)
Wer nun alle Steps durchgearbeitet hat, kann nun gerne die Aufgaben im nächsten Step bearbeiten ;-)