Registriert seit: 1. Jul 2009
60 Beiträge
|
Re: Zuweisung in einer anderen Klasse
15. Sep 2009, 14: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.
|
|
Zitat
|