2011-11-08 30 views
11

Trong Delphi XE2, tôi đang cố gắng quá tải toán tử in trên bản ghi để cho phép tôi kiểm tra xem giá trị được đại diện bởi bản ghi có phải là một phần của tập hợp hay không. Mã của tôi trông giống như sau:Quá trình vận hành của nhà khai thác Delphi trong một tập hợp

type 
    MyEnum = (value1, value2, value3); 
    MySet = set of MyEnum; 
    MyRecord = record 
    Value: MyEnum; 
    class operator In(const A: MyRecord; B: MySet): Boolean; 
    end; 

class operator MyRecord.In(const A: MyRecord; B: MySet): Boolean; 
begin 
    Result := A.Value in B; 
end; 

procedure TForm1.Button1Click(Sender: TObject); 
var 
    R: MyRecord; 
    S: MySet; 
begin 
    R.Value := value1; 
    S := [value1, value2]; 
    Button1.Caption := BoolToStr(R in S); 
end; 

Mã không biên dịch được. Đối với tuyên bố R in S trình biên dịch cho biết: Các loại không tương thích MyRecordMyEnum.

Tôi làm cách nào để quá tải nhà điều hành In trên MyRecord để R in S sẽ đánh giá True trong mã ở trên?

+1

Tôi không nghĩ rằng những gì bạn đang cố gắng đạt được là có thể ... bạn nên có may mắn hơn viết một ký tự phụ ".Value" => BoolToStr (R.Value in S); và được thực hiện với nó – ComputerSaysNo

+0

Mã trong câu hỏi của tôi chỉ là một mẫu đơn giản. Trong ứng dụng thực tế của tôi, loại bản ghi không có sự tương ứng trực tiếp với loại thiết lập. Cách giải quyết mà tôi đã sử dụng là thêm một hàm 'InSet (S: MySet): Boolean' vào bản ghi và sử dụng nó thay vì toán tử' in'. –

+0

có thể đủ tốt sẽ làm cho hàm thành viên thay thế - 'BoolToStr (R._in (S)); ' –

Trả lời

1

Vâng, bạn có thể gần làm điều này, nhưng bạn có thể không muốn. AFAIK, các toán tử lớp chỉ hoạt động trên lớp (hoặc bản ghi) chúng được định nghĩa bên trong, vì vậy cả R và S trong mã của bạn phải là TMyRecord. Với một số sử dụng khờ của ép kiểu ngầm, chúng tôi nhận được như sau:

unit Unit2; 
interface 
type 
    MyEnum = (value1, value2, value3); 
    MySet = set of MyEnum; 
    MyRecord = record 
    Value: MyEnum; 
    ValueSet: MySet; 
    class operator Implicit(A: MyEnum): MyRecord; 
    class operator Implicit(A: MySet): MyRecord; 
    class operator In (Left,Right:MyRecord): Boolean; 
    end; 

implementation 

class operator MyRecord.Implicit(A: MyEnum): MyRecord; 
begin 
    Result.Value := A; 
end; 

class operator MyRecord.Implicit(A: MySet): MyRecord; 
begin 
    Result.ValueSet := A; 
end; 

class operator MyRecord.In(Left, Right: MyRecord): Boolean; 
begin 
    Result:= left.Value in Right.ValueSet; 
end; 
end. 

Sau đây bây giờ sẽ hãy biên dịch, và thậm chí làm việc:

procedure TForm1.Button1Click(Sender: TObject); 
var 
    R: MyRecord; 
    S: MyRecord; 
begin 
    R.Value := value1; 
    S := [value1,value2,value3]; 
    Button1.Caption := BoolToStr(R In S,true); 
end; 

nào, tôi chắc chắn rằng tất cả chúng ta sẽ đồng ý, có nhiều thanh lịch hơn 'BoolToStr (R.Value in S)'. Tuy nhiên những điều sau đây cũng sẽ biên dịch, nhưng cho kết quả sai:

procedure TForm1.Button1Click(Sender: TObject); 
var 
    R: MyRecord; 
    S: MyRecord; 
begin 
    R.Value := value1; 
    S := [value1,value2,value3]; 
    Button1.Caption := BoolToStr(S In R,true); 
end; 

Vì vậy, như Dorin nhận xét, tốt hơn để chỉ có ngu si đần độn, ù lì cũ 'BoolToStr (R.Value trong S)'. Trừ khi tất nhiên bạn đang được trả tiền cho mỗi dòng mã. Và tiền thưởng để sửa lỗi.

+0

Câu hỏi đặc biệt này chỉ là một bài tập trong việc tìm ra các toán tử lớp mà tôi chưa từng sử dụng trước đây. Loại bản ghi trong mã thực tế mà tôi đang làm việc phức tạp hơn rất nhiều. Các toán tử mà nó định nghĩa cho phép mã sử dụng bản ghi đó đơn giản hơn nhiều. Một vài trăm dòng hàm vận hành đơn giản cho phép hàng ngàn dòng mã phức tạp có thể đọc được nhiều hơn. –

+0

Xin lỗi, nhận xét của tôi hơi có phần. Tôi thừa nhận tôi rất được chụp với người vận hành mới đang tải hồ sơ, và đang sử dụng nó rộng rãi. Và tôi đồng ý rằng nó làm cho mã rõ ràng hơn trong nhiều trường hợp. Tôi chỉ chọc vào giải pháp của riêng mình, vì nó là quá mức cần thiết trong trường hợp này ;-) – HMcG

+0

"vì vậy cả R và S trong mã của bạn phải là TMyRecord" điều này là không chính xác. – Johan

5

Để toán tử in hoạt động đúng toán hạng phải thuộc loại bản ghi vì đó là toán tử được đặt chứ không phải toán tử nhị phân. Trong trường hợp của bạn, nó là toán hạng bên trái.

Vì vậy, sau đây sẽ làm việc:

type 
    MyRecord = record 
    Value: MyEnum; 
    class operator In(const A: MyRecord; const B: MySet): Boolean; 
    end; 

    MyRecord2 = record 
    Value: MySet; 
    class operator In(const A: MyRecord; const B: MyRecord2): Boolean; 
    class operator In(const A: MyEnum; const B: MyRecord2): Boolean; 
    end; 

class operator MyRecord.In(const A: MyRecord; const B: MySet): Boolean; 
begin 
    Result := A.Value in B; 
end; 

class operator MyRecord2.In(const A: MyRecord; const B: MyRecord2): Boolean; 
begin 
    Result := A.Value in B.Value; 
end; 

class operator MyRecord2.In(const A: MyEnum; const B: MyRecord2): Boolean; 
begin 
    Result := A in B.Value; 
end; 

procedure TForm1.Button1Click(Sender: TObject); 
var 
    R: MyRecord; 
    R2: MyRecord2; 
begin 
    R.Value := value1; 
    R2.Value := [value1, value2]; 

    if R in R2 then; 
    if value1 in R2 then; 
end; 
Các vấn đề liên quan