Konstruktory


Konstruktor jest specjalną metodą, która kreuje i inicjalizuje obiekt. Deklaracja konstruktora wygląda jak deklaracja procedury, ale rozpoczyna sie słowem constructor zamiast procedure. Przykłady:

constructor Create;
constructor Create(AOwner: TComponent);

Konstruktory muszą używać domyślnej konwencji wywołań rejestracji. Chociaż deklaracja nie specyfikuje wartości zwracanej, to kiedy konstruktor jest wywoływany w kwalifikacji z nazwą klasy, zwraca on odwołanie do wykreowanego obiektu tej klasy.

Klasa może mieć więcej konstruktorów, ale większość posiada tylko jeden. Zgodnie z przyjętą konwencją konstruktory nazywane są słowem Create.

Przykład wykreowania obiektu MyObject klasy TMyClass:

MyObject := TMyClass.Create;

Wywołanie powoduje przydzielenie pamięci na stosie na użytek nowego obiektu, wyzerowanie wartości wszystkich wartości pól typu porządkowego, podstawienie wartości nil do pól typu pointer i klasowego, oraz ustawienie wszystkich pól łańcuchowych jako pustych. Inne operacje specyfikowane w konstruktorach to zwykle inicjowanie podstawowych wartości przekazywanych przez parametry do konstruktora. W końcu konstruktor zwraca odwołanie do nowo alokowanego i zainicjowanego obiektu. Typ zwracanej wartości jest taki sam jak typ klasy wyspecyfikowany w wywołaniu konstruktora.

W razie wystąpienia błędu podczas egzekucji konstruktora, automatycznie wykonywane jest wywołanie destruktora w celu usunięcia z pamięci niedokończonego obiektu.

Kiedy konstruktor jest wywoływany w kwalifikacji z identyfikatorem obiektu a nie klasy, nie kreuje nowego obiektu, ani nie zwraca żadnych wartości. Zamiast tego, konstruktor operując na wyspecyfikowanym obiekcie, wykonuje tylko pozostałe zaimplementowane operacje. Zwykle konstruktor jest wywoływany w kwalifikacji z identyfikatorem obiektu w połączeniu z dyrektywą inherited aby uruchomić odziedziczony konstruktor.

Przykład typu klasowego i jego konstruktora:

type
  TShape = class(TGraphicControl)
  private
    FPen: TPen;
    FBrush: TBrush;
    procedure PenChanged(Sender: TObject);
    procedure BrushChanged(Sender: TObject);
  public
    constructor Create(Owner: TComponent); override;
    destructor Destroy; override;
    ...
  end;

constructor TShape.Create(Owner: TComponent);
begin
  inherited Create(Owner);  // inicjalizacja części odziedziczonych
  Width := 65;              // zmiana odziedziczonych właściwości
  Height := 65;
  FPen := TPen.Create;      // inicjalizacja nowych pól;
  FPen.OnChange := PenChanged;
  FBrush := TBrush.Create;
  FBrush.OnChange := BrushChanged;
end;

Pierwszą czynnością konstruktora jest zwykle wywołanie konstruktora odziedziczonego w celu inicjalizacji odziedziczonych pól. Później konstruktor inicjuje pola przedstawione w typie potomnym. Ponieważ konstruktor zawsze czyści miejsce pod alokację nowego obiektu, wszystkie pola są zerowane (typy porządkowe), podstawiana jest wartość nil (typy pointer i class), usuwana jest zawartość łańcuchów (typ string), podstawiana jest wartość Unassigned (typ variant). Dlatego nie ma potrzeby inicjowania pól jeśli ma to być tylko "zerowanie".

Wywołany w kwalifikacji z identyfikatorem klasy konstruktor, zadeklarowany jako virtual, jest równoważny z konstruktorem statycznym. Mimo to, łączone z identyfikatorem klasy wirtualne konstruktory, umożliwiają polimorficzne konstrukcje obiektów — t.j., konstrukcje obiektów, o typach niezdeterminowanych podczas kompilacji.