Eigentlich ist es ganz simpel, wenn man den Überblick hat:
Es gibt grundsätzlich die Unterscheidung zwischen
statischen und
virtuellen Methoden. Die
dynamischen rechne ich jetzt den virtuellen zu, da diese sich im Laufzeitverhalten nicht von den virtuellen unterscheiden.
Klassen sind im wesentlichen nichts weiter als erweiterte Records. Eine Klasse enthält zunächst einen Zeiger auf die Virtual Method Table, dann die Felder und dann die Methoden.
Statische Methoden heißen statisch, weil ihre Adresse zur Compilierzeit feststeht. Eine statische Methode wird vom Compiler also wie eine gewöhnliche Funktion behandelt, wenn der Code erzeugt wird. Es wird nur zusätzlich eine Referenz auf das bezogene Objekt mitgegeben.
Bei virtuelle Methoden dagegen wird erst zur Laufzeit die Adresse ermittelt. Das geschieht mit Hilfe der
VMT (s.o)., in der u.a. die Adressen der virtuellen Methoden stehen.
Nun schaue man sich folgendes an:
Delphi-Quellcode:
type
TMyStaticClass = class
public
procedure DoSomething;
end;
TMyStaticDerivedClass = class
public
procedure DoSomething;
end;
TMyVirtualClass = class
public
procedure DoSomething; virtual;
end;
TMyVirtualDerivedClass = class
public
procedure DoSomething; override;
end;
procedure TMyStaticClass.DoSomething;
begin
ShowMessage('1');
end;
procedure TMyStaticDerivedClass.DoSomething;
begin
ShowMessage('2');
end;
procedure TMyVirtualClass.DoSomething;
begin
ShowMessage('3');
end;
procedure TMyVirtualDerivedClass.DoSomething;
begin
ShowMessage('4');
end;
So, jetzt probieren wir etwas rum:
Delphi-Quellcode:
var
o: TMyStaticClass;
begin
o := TMyStaticDerivedClass.Create;
o.DoSomething;
end;
Hier wird '1' ausgegeben. Warum, es wird doch eine Instanz von TMyStaticDerviedClass erzeugt? Ja, aber der Typ der Variablen ist TMyStaticClass, und Typen werden zur Compilierzeit ausgewertet.
Schauen wir uns das ganze mal virtuell an:
Delphi-Quellcode:
var
o: TMyVirtualClass;
begin
o := TMyVirtualDerivedClass.Create;
o.DoSomething;
end;
Hier wird nun 4 ausgegeben. Wir erinnern uns, jedes Objekt enthält einen Zeiger auf die
VMT. Dadurch kann zur Laufzeit, obwohl der tatsächliche Typ unbekannt bzw. maskiert ist, die Adresse der entsprechenden virtuelle Methode ermittelt werden.
Nun zu
override:
Um zu kennzeichnen, dass wir eine virtuelle Methode überschreiben wollen, müssen wir dem override angeben. Die Methode bleibt dadurch virtuell, keine Angst. Geben wir aber kein override an, so verdecken wir die virtuelle Methode. Der Compiler teilt uns das mit, weil er denkt, wir wollen das nicht so. Wenn wir das aber doch wollen, müssen wir ihm das explizit sagen, und dafür ist
reintroduce da.