Constructor

rk7771

Constructor - słowo kluczowe języka Delphi.

Słowo kluczowe constructor służy do deklarowania specjalnych metod zwanych konstruktorami.

Konstruktory służą do tworzenia i inicjalizacji instancji obiektu danej klasy.
Poprzez tworzenie rozumiemy przydzielenie niezbędnej pamięci dla obiektu.
Inicjalizacja to wykonanie czynności początkowych np. przypisanie wartości dla zmiennych. [#]_

W momencie przydzielania pamięci dla obiektu jest ona automatycznie zerowana, tzn wszystkie komórki pamięci mają wartość zero. W związku z tym wszystkie zmienne liczbowe przyjmują wartość zero, zmienne wskaźnikowe -nil, a ciągi znaków są puste.

W przypadku gdy wystąpi błąd w trakcie tworzenia obiektu automatycznie wywołany zostanie destruktor, który zniszczy częściowo stworzony obiekt.

Po utworzeniu obiektu konstruktor zwraca wartość która jest tego samego typu co klasa. Jak widać konstruktor zachowuje się tak jak funkcja, zwraca bowiem pewną wartość, która wykorzystujemy do operowania na obiekcie. Nie definiujemy typu wartości zwracanej bowiem jest to zbyteczne i uznane za niedozwolone.

Deklaracja konstruktora rozpoczyna się od słowa kluczowego constructor. Deklaruje się go tak samo jak zwykłą metodę, tyle że z użyciem słowa kluczowego constructor:

type
  TMyClass = class
  public
    constructor Bar;  
end;

Konstruktor może posiadać dowolną nazwę. W tym przykładzie zadeklarowano konstruktor o nazwie Bar. Zazwyczaj jednak korzystamy z nazwy Create (ang. stwórz). Dlaczego warto używać nazwy Create? Otóż wszystkie klasy wbudowane w Delphi korzystają z tej nazwy, więc warto trzymać się tej konwencji, aby czytanie kodu było łatwiejsze. Ponadto użyta nazwa Bar nie odzwierciedla tego co konstruktor robi. Pozostawimy ją jednak aby wskazać że konstruktor nie musi nazywać się Create.

Mając definicję klasy możemy przejść do stworzenia realnego obiektu. W tym celu należy zadeklarować zmienną która wskazuje na daną klasę:

var
  MyClass : TMyClass;
begin
  MyClass := TMyClass.Bar;

W jednym programie może istnieć kilka obiektów wskazujących na daną klasę:

var
  MyClass : array[0..5] of TMyClass;
  i : Integer;
begin
  for i := 0 to 5 do
  begin
    MyClass[i] := TMyClass.Bar;
  end;
end.

W tym przykładzie 6 elementów tablicy zawiera wskazanie do obiektu, który reprezentuje klasę TmyClass. Należy zwrócić uwagę, iż każdy obiekt jest przechowywany w pamięci osobno - istnieją one niezależne od siebie.

Konstruktorów w klasie może być wiele, mogą również zostać poddane procesowi przeciążania. Domyślnie wszystkie klasy VCL/VCL.NET dziedziczą po klasie głównej - TObject. Ona natomiast zawiera konstruktor o nazwie Create, który jest domyślnym konstruktorem klas VCL. Podobnie jak zwykłe metody - również konstruktory mogą posiadać parametry:

type
  TMyClass = class
  private
  //załóżmy, że mamy taką przykładową zmienną w klasie, którą chcemy ustawić w konstruktorze...
  xPosPrivate: Integer; 
  public
    constructor Bar(xPos, yPos, zPos: Integer; s: String); //konstruktor wieloparametrowy  
end;

W takim wypadku definicja konstruktora również będzie poprzedzona słówkiem constructor:

constructor TMyClass.Bar(xPos, yPos, zPos: Integer; s: String);  
begin
   //...wtedy wewnątrz deklaracji ustawiamy naszą zmienną (self oznacza odwołanie do zmiennej 
   //aktualnej klasy, w której się znajduje)
   self.xPosPrivate:=xPos;                                                                           
end;

Ostatecznie można już stworzyć obiekt naszej klasy:

var 
   oTMyClass: TMyCLass;
begin
   oTMyClass:= TMyCLass.Bar(57,8,15,'Działa');// wywołanie konstruktora
end;

Konstruktory muszą być wywoływane w domyślnej konwencji - Register.

Destruktor używany jest z kolei w celu zniszczenia (zwolnienia) obiektu w momencie gdy jest już on niepotrzebny. Deklaracja destruktora rozpoczyna się od słowa kluczowego destructor.

Zobacz też:


.. [#] Istnieją wyjątki od tej reguły. Zobacz: Metody proste

5 komentarzy

Hmmm zrobilem wlasnei test - mam sobie umoesiclem komponent IBDatabase i przekazalem go do procedury Procedura (var _DB : TIBDatabase ) i procedura operowala na tym konkretnym komponencie, bo po jej zakonczeniu komponent mial zmienione paramentry ( login i haslo ) przez ta procedure.
Co ciekawe tak samo sie to zachowywalo jak wywalilem var przez parametrem procedury - czyli tez operowala na oryginalnym obiekcie , a nie na kopii.
Wiec uznaję, że jest to wskaznik. Podejrzewam, ze jesli bym ten komponent zrobil tak :
IBDatabase := TIBDatabase.Create(nil), to IBDatabase tez bylby wskaznikiem, tak jak przy recznym polozeniu komponentu na formie.
CZyli rozumiem, ze nie trzeba w takich przypadkach uzywac new, bo samo Create jest zarazem konstruktorem jak i przydzielaniem pamieci.

Jaki jest zwiazek konstruktora Create ze wskaznikami i dynamicznym tworzeniem obiektu ? Chodzi mi o to , czy w powyzszym przykladzie zmienna MyClass ( lub w drugim przykadzie tablica MyClass) bedzie zawierala wskaznik do obiektu ( wskazniki do obiektow ) czy tez cale obiekty ? Czy np. jesli do jakiejs procedury przekaze MyClass to zostanie przekazany wskaznik i procedura bedzie wykonywla operacje bezposrednio na MyClass czy moze zostanie utworzona kopia obiektu ?

"Dodatkowo, aby zainicjować klasę, należy zadeklarować zmienną która wskazuje na daną klasę"
chyba raczej żeby móc jej później używać, bo można np:

(TOprogramie.Create(nil)).Show;

a w OnClose TOprogramie dać Action := caFree;
klasa zainicjalizowana, użyta, a zmienna nigdzie nie zadeklarowana ... ;)

Przede wszystkim LINKI!

Małą poprawkę wprowadziłem. Jak piszesz że domyślnie jest słowo "Create" to tak nazywaj, to tworzenie obiektu było jakieś koślawe.

I jestem przeciwko kolorkom, może podkreślenia?