2009-03-24 30 views
7

TObject.InstanceSize trả về 8, nhưng TObject không khai báo bất kỳ thành viên dữ liệu nào. Theo việc thực hiện TObject.ClassType, 4 byte đầu tiên có thể được giải thích như một con trỏ tới siêu dữ liệu TClass của đối tượng. Bất cứ ai biết những gì 4 byte khác của chi phí là có cho?Dữ liệu nào chứa TObject?

EDIT: Dường như đây là đặc trưng cho D2009. Trong các phiên bản cũ, nó chỉ có 4 byte.

Trả lời

11

Trong Delphi 2009, có the ability to have a reference to a synchronization monitor. Xem:

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

... trong System.pas

Ngoài ra, vẫn còn là một con trỏ đến VMT. (Phương pháp ảo Table.) From Delphi in a Nutshell:

Lớp TObject tuyên bố vài phương pháp và một người đặc biệt, ẩn lĩnh vực để lưu trữ một tham chiếu đến lớp của đối tượng. Trường ẩn này trỏ tới bảng phương thức ảo của lớp học (VMT). Mỗi lớp có một VMT duy nhất và tất cả các đối tượng của lớp đó chia sẻ VMT của lớp học.

+0

Cũng giống như vậy. Tham chiếu TClass của lớp sẽ trỏ tới VMT của nó. Vì vậy, nó là cùng 4 byte. 4 cái còn lại là gì? –

+0

(Điều đáng chú ý là cuốn sách đó được viết cách đây 9 năm.Có lẽ chỉ có một lĩnh vực ẩn trở lại sau đó. Bây giờ có vẻ là hai trong số họ.) –

+0

Ngoài ra còn có một màn hình đồng bộ hóa trong D2009. Tôi sẽ cập nhật. –

3

Một đối tượng chứa các mục nhập cho tất cả các trường của nó, cộng thêm không gian để giữ con trỏ vào bảng phương thức ảo. VMT không chỉ chứa các con trỏ phương thức ảo. Tôi giải thích more about the VMT tại trang web của tôi, bao gồm một sơ đồ.

Dường như, Delphi 2009 giới thiệu một trường ẩn khác ngoài con trỏ VMT để giữ màn hình đồng bộ hóa. Bạn có thể xác định xem nó được thêm vào ở đầu hoặc ở cuối của lớp với một số mã đơn giản:

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. 

Nếu nó in giá trị 4, sau đó lĩnh vực giám sát phải ở phần cuối của đối tượng vì 4 chỉ các tài khoản cho kích thước của con trỏ VMT. Nếu nó in giá trị 8, thì trường màn hình phải ở đầu, tiếp giáp với con trỏ VMT.

Tôi hy vọng bạn sẽ tìm thấy màn hình khi bắt đầu. Nếu không, nó có nghĩa là cách bố trí của đối tượng hậu duệ không chỉ đơn giản là bố trí của đối tượng cơ sở với tất cả các trường mới được nối thêm. Nó có nghĩa là bù đắp của trường giám sát phụ thuộc vào loại thời gian chạy của đối tượng và điều đó làm cho việc triển khai phức tạp hơn.

Khi một lớp thực hiện một giao diện, bố cục đối tượng bao gồm nhiều trường bị ẩn. Các trường chứa con trỏ tới giá trị tham chiếu giao diện của đối tượng. Khi bạn có một tham chiếu IUnknown đối tượng, con trỏ nó giữ không giống như con trỏ đến trường VMT của đối tượng, đó là những gì bạn có với tham chiếu đối tượng thông thường. Giá trị con trỏ IUnknown sẽ là địa chỉ của trường bị ẩn. Tôi đã viết more about the layout of classes that implement interfaces.

+0

Không. GetInterfaceTable là một hàm lớp dựa trên một offset từ vị trí VMT. Hãy xem xét việc thực hiện TMonitor.GetFieldAddress. Có vẻ như nó phụ thuộc vào loại thời gian chạy, chính xác như bạn đã mô tả. –

+0

GetInterfaceTable tìm nạp thông tin khác, tách biệt với tham chiếu giao diện. Bảng giao diện được chia sẻ bởi tất cả các cá thể của một lớp, giống như VMT. Tham chiếu giao diện không được chia sẻ bởi các phiên bản khác. Đọc bài viết của tôi để biết thêm về cách bố trí các lớp giao tiếp. –

+0

Tôi không thể kiểm tra nguồn cho TMonitor.GetFieldAddress; Tôi không có Delphi 2009. –

0

Chỉ trong trường hợp ai đó đang tự hỏi tại sao Craig Stuntz' câu trả lời đã được accpepted, xem chú thích cuối cùng của mình về câu trả lời rằng:

Hình như đã được bổ sung trong D2009: http://blogs.embarcadero.com/abauer/2008/02/19/38856 Xem các liên kết trong đó bài để biết chi tiết đầy đủ.

Các vấn đề liên quan