2013-06-15 17 views
8

Tôi muốn sử dụng thủ tục của đối tượng trong một bản ghi, như vậy:Làm cách nào để bao gồm một con trỏ phương thức trong một hằng số đã nhập?

TCommandRec = record 
    name: string; 
    fn: procedure of object; 
end; 

tôi có thể tạo ra một mảng với điều này bằng cách chuyển nhượng:

commands: array [0..1] of TCommandRec; 

... 

commands[0].name := '-help'; 
commands[0].fn := DoHelp; 
commands[1].name := '-load'; 
commands[1].fn := DoLoad; 

Những gì tôi thực sự muốn làm tuyên bố một hằng số:

const 
    cmds: array [0..1] of TCommandRec = 
    (
    (name: '-help'; fn: DoHelp), 
    (name: '-load'; fn: DoLoad) 
); 

Tuy nhiên, tôi gặp lỗi cho DoHelp và DoLoad - Biểu thức không đổi mong đợi. Đây là hai phương thức của một lớp. Có một số cú pháp tôi cần phải sử dụng để làm cho công việc này hoặc tôi bị mắc kẹt xây dựng các mảng tại thời gian chạy?

+0

không, phương pháp con trỏ không đủ điều kiện biểu hiện như không đổi (chủ yếu là do sơ thẩm con trỏ - xem TMethod.Data). – OnTheFly

+0

@ user539484 Con trỏ phương pháp với các đối tượng liên tục là các biểu thức không đổi –

+0

@David Heffernan, bạn có ví dụ không? – OnTheFly

Trả lời

7

Phương pháp của đối tượng là loại được gọi là hai loại con trỏ. Nó bao gồm các thông tin sau:

  1. Địa chỉ của hàm.
  2. Địa chỉ của đối tượng hoặc chủ thể.

Trước đây được biết tại thời gian biên dịch nhưng nói chung sau không được biên dịch. Đó là lý do tại sao bạn thường cần tạo những thứ này trong thời gian chạy.

Nếu bạn có thể sắp xếp đối tượng đó được biết tại thời gian biên dịch thì bạn có thể khai báo một hằng số đã nhập của loại bản ghi. Ví dụ:

type 
    TMyRecord = record 
    Foo: procedure of object; 
    end; 

    TMyStaticClass = class 
    class procedure Foo; 
    end; 

class procedure TMyStaticClass.Foo; 
begin 
end; 

const 
    MyRecord: TMyRecord = (Foo: TMyStaticClass.Foo); 

Tất nhiên, điều đó sẽ hữu ích cho bạn nếu các hàm của bạn có thể tồn tại như phương pháp thể hiện. Tôi chỉ cần thêm mã ở trên để minh họa rằng bạn có thể có các con trỏ phương thức không đổi, miễn là đối tượng là một hằng số thời gian biên dịch.

+0

Tôi thích câu trả lời này - Tôi có thể sử dụng các thủ tục lớp vì lớp chỉ hoạt động như một bộ điều phối cho các đối số dòng lệnh. – imekon

2

Bạn có thể lưu trữ các con trỏ tới phương pháp trong hồ sơ của bạn (chúng được gọi tại thời gian biên dịch, vì vậy không có vấn đề chỉ định chúng trong một định nghĩa const):

TCommandRec = record 
    name: string; 
    fn: Pointer; 
end; 

... 
const 
    cmds: array [0..1] of TCommandRec = 
    (
    (name: '-help'; fn: @DoHelp), 
    (name: '-load'; fn: @DoLoad) 
); 

Sau đó, khi bạn cần phải gọi fn của cmds[i] (tôi giả sử rằng các cuộc gọi xảy ra bên trong cùng lớp trong đó xác định phương pháp DoHelpDoLoad), viết một cái gì đó như:

type TObjectProc = procedure of object; 
var m: TMethod; 
... 
m.Code := cmds[i].fn; 
m.Data := Self; 
TObjectProc(m); 
+0

Trên Delphi hiện đại, bạn có thể chọn sử dụng RTTI kiểu mới cho cách tiếp cận thời gian chạy như vậy. Lưu trữ hằng số tên của phương thức và Gọi qua RTTI trên một cá thể cụ thể. –

+0

Vâng, cảm ơn. Nếu tôi nhớ chính xác, RTTI chỉ hoạt động cho các phương thức 'đã xuất bản'. Nhưng nó kém hiệu quả hơn việc lưu trữ một con trỏ (mặc dù hiệu suất có thể không quan trọng ở đây), và trình biên dịch sẽ không cảnh báo chúng ta nếu chúng ta có lỗi đánh máy trong tên của phương thức hoặc nếu chúng ta đổi tên một phương thức thích hợp trong lớp. – Inspired

+1

Kiểu RTTI mới không dựa trên công bố. Đó là một sự cân bằng giữa hiệu suất và không dựa vào chi tiết triển khai. –

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