korzystanie z metod bez tworzenia obiektu

0

Jako że to mój pierwszy post to witam wszystkich. Podczas tworzenia małego programu natrafiłem na dziwną rzecz, mianowicie możliwość wykonania metody bez tworzenia obiektu danej klasy. Dla lepszego zobrazowania sytuacji kod:

Deklaracje klas

type
  TKlasa1 = class
    procedure ABC;  //ShowMessage('k1');
    constructor Create; //ShowMessage('konstruktor_k1');
  end;

  TKlasa2 = class
  public
    PKLASA: TKlasa1;
    procedure XYZ; // ShowMessage('k2');
  end;
 

Kod testowy:

procedure TEST;
var
  K1: TKlasa1;
  K2: TKlasa2;
begin
 // K1:= nil;
 // K2:= nil;
 // K1 := TKlasa1.Create;
 // K2 := TKlasa2.Create;

  //FreeAndNil(K1);
  K1.ABC; // wyświetla komunikat "k1"
  K2.PKLASA.ABC; // wyświetla komunikat "k1"

{  FreeAndNil(K1);
  FreeAndNil(K2); }
end;
 

Na początku myślałem, że Delphi jakoś automatycznie wywołuje konstruktor klasy "Klasa1", co byłoby trochę dziwne. Po stworzeniu konstruktora okazało się, że tak nie jest. Kolejnym testem było przypisanie wartości "nil" do zmiennej "K1". Niestety oba komunikaty dalej się wyświetlały. Dopiero przypisanie "nil" do zmiennej "K2" dało prawie poprawny rezultat tzn. program wyświetlił jeden komunikat, a na drugim wywalił AV.

Macie jakieś pomysły, dlaczego w testowanym kodzie możliwe jest poprawne wywołanie metody nie statycznej bez stworzenia obiektu?

3

To będzie "działać", dopóki klasa nie korzysta z żadnych jej pól.
Jest to możliwe, ponieważ metody są tak właściwie procedurami/funkcjami, które jako swój pierwszy parametr przyjmują wskaźnik na obiekt; czyli ta metoda "ABC" z punktu widzenia kompilatora wygląda tak (w uproszczeniu oraz po wykonaniu prostego name-manglingu):

Procedure KLASA1__ABC(self: Pointer);
Begin
 // nothing here
End;

Pisząc K1.ABC tak naprawdę wywołujesz KLASA1__ABC(K1);, a jako, wewnątrz metody ABC że nie korzystasz z niczego powiązanego z K1 (czyli tamtejszym self), to nic nie ma prawa się "wywalić".
Zobacz sobie wygenerowany kod assemblerowy dla potwierdzenia.

0

Dzięki za wyjaśnienie. Rzeczywiście w asmie wygląda to tak jak napisałeś, niemniej według mnie jest to trochę dziwne zachowanie. Spodziwałem się, że dla niestworzonego obiektu od razu przy próbie wywołania metody wyrzuci błąd.

0

Cóż, jeżeli stworzysz bardziej zaawansowaną klasę z metodami wirtualnymi etc., to wtedy rzeczywiście może się wywalić, ponieważ kompilator (czy raczej skompilowany program) raczy zerknąć do VMT (tabeli wirtualnych metod/virtual method table), czyli spróbuje odczytać niezaalokowane dane, co z kolei skończy się Access Violationem.

0

Jest też coś takiego jak class metod: http://delphi.about.com/od/objectpascalide/a/classmethods.htm

0

@Tajiri - jest taka możliwość, należy skorzystać z metod statycznych; Dzięki temu będziesz mógł wykorzystać metodę bez tworzenia obiektu;

Przykład:

{$APPTYPE CONSOLE}

type
  TFoo = class(TObject)
    class procedure ShowSomeText();
  end;

  class procedure TFoo.ShowSomeText();
  begin
    Write('This is some text');
  end;

begin
  TFoo.ShowSomeText();
  ReadLn;
end.

Po wykonaniu tego programu w oknie konsoli zostanie wyświetlony napis This is some text.

1 użytkowników online, w tym zalogowanych: 0, gości: 1