Einzelnen Beitrag anzeigen

fajac

Registriert seit: 1. Jul 2009
60 Beiträge
 
#9

Re: Zuweisung in einer anderen Klasse

  Alt 15. Sep 2009, 13:32
Hallo martin_

mir scheint, dir ist nicht ganz klar was da passiert. Ich habe deinen Code mal leicht verändert und versucht zu kommentieren, was da "hinter der Bühne" passiert:

Delphi-Quellcode:
type
  TClassA = class (TObject)
  public
    ValueA : Integer;
    function Print : AnsiString; virtual;
  end;

  TClassB = class (TClassA)
  public
    ValueB : Integer;
    ValueC : Integer;
    function Print : AnsiString; override;
    function PrintEx : AnsiString;
  end;

implementation

{ TClassA }

function TClassA.Print: AnsiString;
begin
  Result := IntToStr(ValueA);
end;

{ TClassB }

function TClassB.Print: AnsiString;
begin
  Result := Format ('%d, %d, %d', [ValueA, ValueB, ValueC]);
end;

function TClassB.PrintEx: AnsiString;
begin
  Result := Format ('%d, %d, %d', [ValueA, ValueB, ValueC]);
end;

{ Aufruf }
procedure Test;
var
  A : TClassA; { Das hier ist ein Pointer auf eine Datenstruktur der Klasse TClassA }
  B : TClassB; { Das hier ist ein Pointer auf eine Datenstruktur der Klasse TClassB }
begin
  { Variante A }
  A := TClassA.Create; { Hier wird eine Instanz der Klasse TClassA erzeugt. D.h., es wird soviel Speicher
                         alloziert, wie eine solche Instanz braucht, und der Zeiger A zeigt auf diese Daten. }

  { Variante B }
  // A := TClassB.Create; { Im Vergleich dazu wird hier eine Instanz von TClassB erzeugt und nur als eine
                            vom Typ TClassA betrachtet. Das ist korrekt, da TClassB von TClassA abgeleitet ist. }
  A.ValueA := TClassA.InstanceSize; { Speichere die Größe der Klasseninstanz von TClassA in ValueA }

  B := TClassB(A); { Hier sagst du Delphi, dass der Pointer B auf dieselbe Adresse zeigen soll wie A. Außerdem
                        soll die dort liegende Struktur als eine vom Typ TClassB betrachtet werden, egal ob die
                         beiden kompatibel sind. Das wird [i]mindestens[/i] zu unerwarteten Ergebnissen führen. }

  
  B.ValueB := TClassB.InstanceSize; { Speichere die Größe der Klasseninstanz von TClassA in ValueB }

  { Hier wird in der virtuellen Methodentabelle nachgesehen, welche Methode aufgerufen werden soll. Im Fall der
    Variante A ist das TClassA.Print. }

  ShowMessage (B.Print);
  { Hier wird im Fall der Variante A auf eine Methode zugegriffen, die es in der Methodentabelle von TClassA gar
    nicht gibt! Wenn das nicht scheppert, ist es eher Zufall. }

  ShowMessage (B.PrintEx);
end;
Probier mal beide Varianten aus und lass dich überraschen, was heraus kommt.
  Mit Zitat antworten Zitat