2009-03-24 13 views
7

TObject.InstanceSize zwraca 8, ale TObject nie deklaruje żadnych elementów danych. Zgodnie z implementacją TObject.ClassType pierwsze 4 bajty można wyjaśnić jako wskaźnik do metadanych obiektu TClass. Czy ktoś wie, jakie są pozostałe 4 bajty narzutów?Jakie dane zawiera TObject?

EDYCJA: Wygląda na to, że jest to specyficzne dla D2009. W starszych wersjach to tylko 4 bajty.

Odpowiedz

11

W Delphi 2009 jest the ability to have a reference to a synchronization monitor. Zobacz:

class function TMonitor.GetFieldAddress(AObject: TObject): PPMonitor; 
class function TMonitor.GetMonitor(AObject: TObject): PMonitor; 

... w System.pas

Ponadto, nadal istnieje wskaźnik do VMT. (Virtual Metoda stołowy.) From Delphi in a Nutshell:

Klasa TObject deklaruje kilka metod i jedną specjalną, ukryte pole przechowywać odwołanie do obiektu klasie. To ukryte pole wskazuje na wirtualną tabelę metod klasy VMT ( ). Każda klasa ma unikatowy obiekt VMT i wszystkie obiekty należące do tej klasy o wartości mają klasę VMT klasy .

+0

To dokładnie to samo. Punkt odniesienia klasy TClass wskazuje na jej VMT. Więc to są te same 4 bajty. Jakie są pozostałe 4? –

+0

(Warto zauważyć, że ta książka została napisana 9 lat temu.Może wtedy było tylko jedno ukryte pole. Wygląda na to, że są dwie.) –

+0

Istnieje również monitor synchronizacji w D2009. Zaktualizuję. –

3

Obiekt zawiera wpisy dla wszystkich swoich pól oraz dodatkowe miejsce na wskaźnik do tabeli metod wirtualnych. VMT posiada więcej niż wskaźniki wirtualnej metody. Wyjaśniam more about the VMT na mojej stronie internetowej, w tym diagram.

Podobno Delphi 2009 wprowadza inne ukryte pole oprócz wskaźnika VMT do przechowywania monitora synchronizacji. Można określić, czy jest on dodawany na początku lub na końcu klasy z jakiegoś prostego kodu:

type 
    TTest = class 
    FField: Integer; 
    end; 

var 
    obj: TTest; 
    ObjAddr, FieldAddr: Cardinal; 
begin 
    Assert(TTest.InstanceSize = 12); 
    obj := TTest.Create; 
    ObjAddr := Cardinal(obj); 
    FieldAddr := Cardinal(@(obj.FField)); 
    writeln(FieldAddr - ObjAddr); 
end. 

Jeśli drukuje wartość 4, a następnie w polu monitor musi być na końcu obiektu, ponieważ 4 uwzględnia tylko wielkość wskaźnika VMT. Jeśli wypisze wartość 8, pole monitora musi znajdować się na początku, obok wskaźnika VMT.

Oczekuję, że znajdziesz monitor na starcie. W przeciwnym razie oznacza to, że układ obiektu potomnego nie jest po prostu układem obiektu bazowego z dołączonymi wszystkimi nowymi polami. Oznaczałoby to przesunięcie pola monitora w zależności od typu obiektu, co powoduje, że implementacja jest bardziej skomplikowana.

Gdy klasa implementuje interfejs, układ obiektu zawiera więcej ukrytych pól. Pola zawierają wskaźniki do wartości odniesienia dla interfejsu obiektu. W przypadku odwołania do obiektu o wartości IUnknown wskazany przez niego wskaźnik nie jest tym samym, co wskaźnik do pola VMT obiektu, czyli tym, co mamy w przypadku zwykłego odwołania do obiektu. Wartość wskaźnika IUnknown będzie adresem ukrytego pola. Napisałem more about the layout of classes that implement interfaces.

+0

Nie. GetInterfaceTable to funkcja klasy oparta na offsecie od lokalizacji VMT. Spójrz na implementację TMonitor.GetFieldAddress. Wygląda na to, że zależy to od typu uruchamiania, dokładnie tak, jak opisałeś. –

+0

Funkcja GetInterfaceTable pobiera coś innego, niezależnie od odwołania do interfejsu. Tabela interfejsu jest współużytkowana przez wszystkie instancje klasy, podobnie jak VMT. Odwołanie do interfejsu nie jest współużytkowane przez inne instancje. Przeczytaj mój artykuł, aby dowiedzieć się więcej o układzie klas z interfejsem. –

+0

Nie mogę sprawdzić źródła dla TMonitor.GetFieldAddress; Nie mam Delphi 2009. –