Delphi'de bir metot virtual olarak belirtilmediğinde o metot sanal olmaz statik olur. Peki virtual'ın farkı nedir? Bunu şu şekilde anlatabiliriz;
Bir ata sınıfın tanımlanmış bir sanal metodunu onun çocuğu olan bir sınıfta ezdiğimiz (override) zaman, ata sınıfı göstererek bu metodu çalıştırdığımızda, çocuk sınıfın metodu çalışacaktır.
Örnekleyelim;
uses System.SysUtils, System.Contnrs; type TMeyve = class strict private FMeyveCinsi : string; FMeyveMiktari : string; public property MeyveCinsi : string read FMeyveCinsi write FMeyveCinsi; property MeyveMiktari: string read FMeyveMiktari write FMeyveMiktari; procedure Topla; virtual; end; TAgaclar = class private FMeyveAgaclari : TObjectList; public constructor Create; destructor Destroy; override; procedure AgacEkle(agac : TMeyve); procedure MeyveleriTopla; end; TElma = class(TMeyve) constructor Create; procedure Topla; override; end; TArmut = class(TMeyve) constructor Create; procedure Topla; end;
Burada önce bir TMeyve ata sınıfı tanımlıyoruz, bundan türetilmiş TElma ve TArmut meyveleri var. Bunların ikisinin de Create yapılandırıcısı (constructor) ve Topla metodu var. Ancak TElma'nın Topla metodu öncekini ezmiş TArmut'un Topla metodu bilindik statik metot. Şimdi bunların kodlarını da şu şekilde yazarsak,
{ TMeyve }
procedure TMeyve.Topla;
begin
Writeln(MeyveCinsi+' toplanmadı');
end;
{ TAgac }
procedure TAgaclar.AgacEkle(agac: TMeyve);
begin
FMeyveAgaclari.Add(agac);
end;
constructor TAgaclar.Create;
begin
FMeyveAgaclari := TObjectList.Create;
end;
destructor TAgaclar.Destroy;
begin
FMeyveAgaclari.Destroy;
inherited;
end;
procedure TAgaclar.MeyveleriTopla;
var
meyve: TMeyve;
begin
for meyve in FMeyveAgaclari do
begin
meyve.Topla;
end;
end;
{ TElma }
constructor TElma.Create;
begin
MeyveCinsi := 'Elma';
MeyveMiktari := '15 adet';
end;
procedure TElma.Topla;
begin
Writeln(MeyveMiktari+' '+MeyveCinsi+' toplandı...');
end;
{ TArmut }
constructor TArmut.Create;
begin
MeyveCinsi := 'Armut';
MeyveMiktari := '81 adet';
end;
procedure TArmut.Topla;
begin
Writeln(MeyveMiktari+' '+MeyveCinsi+' toplandı...');
end;
var
agaclar : TAgaclar;
begin
try
agaclar := TAgaclar.Create;
try
agaclar.AgacEkle(TElma.Create);
agaclar.AgacEkle(TArmut.Create);
agaclar.MeyveleriTopla;
Readln;
finally
agaclar.Free;
end;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
Burada meyve listesini tutmak için TObjectList (geleneksel list, generic değil) kullandım. TList te kullanabilirdim. Ancak TList pointer listesi için kullanıldığından dolayı listenin işi bitince free yapıldığında nesneleri free yapamaz. TObjectList ise free edildiğinde listedeki tüm nesneleri de yok edecektir.
Bu örnek konsol uygulaması olarak çalıştırılabilir. Bir console uygulaması oluşturup içindekiler yerine bunları kopyalarsanız test edebilirsiniz.
Not : Bu örnekler Delphi 10.1 Berlin Delphi 10.2 Tokio için denenmiştir.