Thunderlane napisał(a)
Tak się zastanawiałem, czy istnieje w Delphi możliwość wywołania pola/metody obiektu nieokreślonej klasy, a potem w innym miejscu w kodzie określenia jaka to klasa?
Nie, taka możliwość nie istnieje - zawsze musi być wiadomo z której klasy zostaje wywołana metoda;
Thunderlane napisał(a)
Załóżmy, że mamy kilka podobnych klas wykonujących te same operacje ale każda eksportuje wyniki do pliku o innym rozszerzeniu. Teraz chcę napisać funkcję wykonującą kilka operacji wspólnych dla wszystkich tych klas, a następnie eksportującą wynik do pliku.
W najlepszym wypadku wszystkie te klasy będą spokrewnione, o czym napisał poprzednik; Jeżeli wszystkie dziedziczą z tej samej klasy bazowej, to możesz korzystać ze wszystkiego, co posiada właśnie ta klasa bazowa (z wyjątkiem metod abstrakcyjnych oraz tych, które nie posiadają definicji, ale są zadeklarowane);
Przykładem jest korzystanie np. z bazowej klasy strumieni TStream
; Jeżeli zadeklarujesz sobie w jakiejś metodzie parametr tej klasy, to możesz w nim przekazać referencję do instancji klasy TStream
, TFileStream
, TMemoryStream
czy TStringStream
, czyli wszystkich klasy dziedziczących z TStream
oraz nią samą; Ale to nie zmienia faktu, że cokolwiek by się nie przekazało w parametrze - dostęp będzie jedynie do składowych klasy TStream
; Podobnie będzie w Twoim przypadku - będziesz mógł skorzystać jedynie ze składowych klasy bazowej, o ile taka istnieje;
Wymyślony przykład z dziedziczeniem klas do obsługi zapisu plików bmp
i svg
, dziedziczących z jednej klasy bazowej;
type
TPictureObject = class(TObject)
public
procedure SaveToFile(AFileName: TFileName); virtual;
end;
procedure TPictureObject.SaveToFile(AFileName: TFileName);
begin
raise Exception.Create('cannot save picture to file in base class');
end;
type
TBitmapObject = class(TPictureObject)
public
procedure SaveToFile(AFileName: TFileName); override;
end;
procedure TBitmapObject.SaveToFile(AFileName: TFileName);
begin
WriteLn('saving to BMP file: ', AFileName);
end;
type
TSVGObject = class(TPictureObject)
public
procedure SaveToFile(AFileName: TFileName); override;
end;
procedure TSVGObject.SaveToFile(AFileName: TFileName);
begin
WriteLn('saving to SVG file: ', AFileName);
end;
procedure SavePictureToFile(APicture: TPictureObject; AFileName: TFileName);
begin
APicture.SaveToFile(AFileName);
end;
var
bmpObject: TBitmapObject;
svgObject: TSVGObject;
begin
bmpObject := TBitmapObject.Create();
svgObject := TSVGObject.Create();
try
SavePictureToFile(bmpObject, 'C:\Picture.bmp');
SavePictureToFile(svgObject, 'C:\Picture.svg');
finally
bmpObject.Free();
svgObject.Free();
end;
end.
Na wyjściu otrzymamy:
saving to BMP file: C:\Picture.bmp
saving to SVG file: C:\Picture.svg
A teraz przykład z brakiem powiązania pomiędzy tymi klasami:
type
TBitmapObject = class(TObject)
public
procedure SaveToFile(AFileName: TFileName);
end;
procedure TBitmapObject.SaveToFile(AFileName: TFileName);
begin
WriteLn('saving to BMP file: ', AFileName);
end;
type
TSVGObject = class(TObject)
public
procedure SaveToFile(AFileName: TFileName);
end;
procedure TSVGObject.SaveToFile(AFileName: TFileName);
begin
WriteLn('saving to SVG file: ', AFileName);
end;
procedure SavePictureToFile(APicture: TObject; AFileName: TFileName);
begin
if APicture is TBitmapObject then
TBitmapObject(APicture).SaveToFile(AFileName)
else
if APicture is TSVGObject then
TSVGObject(APicture).SaveToFile(AFileName)
else
raise Exception.Create('unknown object to save to file');
end;
var
bmpObject: TBitmapObject;
svgObject: TSVGObject;
begin
bmpObject := TBitmapObject.Create();
svgObject := TSVGObject.Create();
try
SavePictureToFile(bmpObject, 'C:\Picture.bmp');
SavePictureToFile(svgObject, 'C:\Picture.svg');
finally
bmpObject.Free();
svgObject.Free();
end;
end.
Wyjście będzie dokładnie takie samo jak w poprzednim przkładnie, jednak procedura SavePictureToFile
musi działać inaczej - sprawdzać co zostało przekazane w parametrze APicture
i wykonać rzutowanie;
Sprawdź więc jak wygląda hierarchia Twoich dwóch klas i wybierz obpowiednią metodę ich obsługi.