(dodałem tę odpowiedź, bo IMHO gdzie inni nie kompletna)
Metoda 2 jest prawidłowa.
Metoda 1, jeśli nie zostanie wywołana, ponieważ do wywołania konstruktora jest ukryty parametr, który może nie zadziałać prawidłowo, iniatialize: w rzeczywistości NewInstance
jest pseudo-wirtualną metodą klasy!
Rzeczywiście, w wywołaniu konstruktora istnieje ukryty parametr boolean
(rejestr EDX
, od EAX
= klasa). Jak stwierdził official documentation:
konstruktorów i destruktorów używać tych samych konwencji telefoniczne innych metod, oprócz tego, że dodatkowy parametr Boolean
flaga jest przekazywana do wskazania kontekstu konstruktora lub destruktora rozmowy.
Wartość False
w parametrze flag wywołania konstruktora wskazuje, że konstruktor został wywołany przez obiekt instancji lub za pomocą odziedziczonego słowa kluczowego. W takim przypadku konstruktor zachowuje się tak jak zwykła metoda. Wartość True
w parametrze flag wywołania konstruktora wskazuje, że konstruktor został wywołany przez odwołanie klasy . W takim przypadku konstruktor tworzy instancję z class
podaną przez Self
i zwraca odniesienie do nowo utworzonego obiektu w EAX
.
W szczególności, po wywołaniu w ten sposób, klasa nie wywoła funkcji _ClassCreate
. Inicjowanie klasy może się nie powieść, jeśli klasa nie ma być utworzona z domyślną funkcją NewInstance
. W rzeczywistości ta funkcja jest wstawiana do klasy VMT: w rzadkich przypadkach może być przeciążona (np. W celu zapewnienia innego schematu alokacji pamięci - może to być zbieracz pamięci lub zoptymalizowany pod kątem szybkości program przydzielania). Dlatego wywołanie bezpośrednio InstanceClass.NewInstance
może być błędne, w niektórych przypadkach granicznych.
function _ClassCreate(AClass: TClass; Alloc: Boolean): TObject;
asm
...
TEST DL,DL
JL @@noAlloc
CALL dword ptr [EAX].vmtNewInstance
@@noAlloc:
...
Dlatego dzwoniąc InstanceClass.NewInstance
bezpośrednio jest tylko zostać zrobione celowo, tylko jeśli chcesz anulować dwa nadpisane vmtNewInstance/vmtFreeInstance
(aw tym przypadku może być również NIE zadzwonić .Free/.Destroy
, ale jesteś właścicielem pamięci darmową funkcję). Tak więc: nigdy nie dzwoń pod numer NewInstance
, ale constructor
, zaprojektowany i udokumentowany przez zespół Embarcadero (i przy okazji zespół FreePascal), chyba że musisz wprowadzić jakieś wewnętrzne ulepszenia niskiego poziomu.
NIGDY nie używaj metody 1 do tworzenia obiektu! Może działać przez 99,9% czasu, ale może się nie udać w niektórych przypadkach lub z rozszerzeniem kompilatora/RTL w przyszłości (jak odśmiecacz). Nawet jeśli VCL czasami używa NewInstance
, nie powinieneś go używać - wolałbym, aby ta metoda była chroniona.
Warto wiedzieć, dlaczego zmienna formularza jest wymagana przed zakończeniem konstruktora formularzy? – kludg
@Serg Myślę, że to nieprawda. To prawdopodobnie relikt z bardzo wczesnego VCL. Wydaje się błędne użycie odniesienia do częściowo skonstruowanego obiektu. Nie uważałbym tego za dobry styl. Myślę, że to tylko dziedzictwo. –
Zdecydowanie nie jest to dobry styl, ale formy mają szczególną rolę w VCL i IDE, więc może to być poważny powód. – kludg