2013-04-24 34 views
6

Tôi muốn quá tải chỉ có một loại cuộc gọi subsref (loại '()' cho một lớp cụ thể và để lại bất kỳ cuộc gọi nào khác để xây dựng trong subsref của Matlab - cụ thể, tôi muốn Matlab xử lý truy cập thuộc tính/phương thức thông qua '.' kiểu. Nhưng, có vẻ như chức năng 'builtin' của Matlab không hoạt động khi subsref bị quá tải trong một lớp.Tại sao tôi không thể sử dụng nội trang cho các lớp quá tải subref?

xem xét lớp này:

classdef TestBuiltIn 
    properties 
     testprop = 'This is the built in method'; 
    end 

    methods 
     function v = subsref(this, s) 
      disp('This is the overloaded method'); 
     end 
    end 
end 

Để sử dụng phương pháp subsref quá tải, tôi làm điều này:

t = TestBuiltIn; 
t.testprop 
    >> This is the overloaded method 

Đó là như mong đợi. Nhưng bây giờ tôi muốn gọi Matlab được xây dựng trong phương pháp subsref. Để đảm bảo tôi đang làm đúng, trước tiên, tôi thử một cuộc gọi tương tự trên cấu trúc:

x.testprop = 'Accessed correctly'; 
s.type = '.'; 
s.subs = 'testprop'; 
builtin('subsref', x, s) 
    >> Accessed correctly 

Điều đó cũng đúng như mong đợi. Nhưng, khi tôi thử phương pháp tương tự trên TestBuiltIn:

builtin('subsref', t, s) 
    >> This is the overloaded method 

... Matlab gọi phương thức quá tải thay vì phương pháp được tích hợp sẵn. Tại sao Matlab gọi phương thức bị quá tải khi tôi yêu cầu phương thức được xây dựng?

CẬP NHẬT: Để trả lời câu trả lời của @Andrew Janke, giải pháp đó hầu như hoạt động nhưng không hoàn toàn. Xem xét lớp này:

classdef TestIndexing 
    properties 
     prop1 
     child 
    end 

    methods 
     function this = TestIndexing(n) 
      if nargin==0 
       n = 1; 
      end 

      this.prop1 = n; 
      if n<2 
       this.child = TestIndexing(n+1); 
      else 
       this.child = ['child on instance ' num2str(n)]; 
      end 
     end 

     function v = subsref(this, s) 
      if strcmp(s(1).type, '()') 
       v = 'overloaded method'; 
      else 
       v = builtin('subsref', this, s); 
      end 
     end 
    end 
end 

Tất cả điều này hoạt động:

t = TestIndexing; 
t(1) 
    >> overloaded method 
t.prop1 
    >> 1 
t.child 
    >> [TestIndexing instance] 
t.child.prop1 
    >> 2 

Nhưng điều này không làm việc; Nó sử dụng được xây dựng trong subsref cho đứa trẻ chứ không phải là subsref quá tải:

t.child(1) 
    >> [TestIndexing instance] 

Lưu ý rằng hành vi trên là không phù hợp với cả hai hành vi (được như dự kiến):

tc = t.child; 
tc(1) 
    >> overloaded method 

x.child = t.child; 
x.child(1) 
    >> overloaded method 
+0

Không chắc chắn nếu tôi hoàn toàn hiểu, nhưng tôi nghĩ rằng đầu tiên hàm dựng sẵn được gọi, và sau đó trong cuộc gọi đó phương thức nạp chồng được gọi. Nếu có thể đặt một điểm dừng ở một vị trí hữu ích. –

+0

Một cái gì đó hoàn toàn khác nhau: Tôi hy vọng bạn chỉ cần cố gắng làm điều này ra khỏi lợi ích cá nhân, như đối với hầu hết các vấn đề quá tải subsref có thể không phải là giải pháp tốt nhất. –

+0

Tôi không chắc chắn ý nghĩa của hàm dựng sẵn được gọi là đầu tiên - nếu đó là giả thuyết (không chắc chắn như thế nào, nhưng nói), tôi nghĩ tôi sẽ cần thiết lập một điểm ngắt bên trong chức năng subsref được xây dựng của Matlab để xác minh . Nhưng đó là một chức năng bản địa chứ không phải là một hàm m, vì vậy tôi không thể đặt một điểm dừng ở đó. – Ben

Trả lời

4

Có thể , IIRC. Để thay đổi () nhưng không phải {} và '.', Hãy viết phương thức subsref của bạn để chuyển các trường hợp khác cùng với thẻ phụ được xây dựng từ bên trong quá trình đăng ký bị quá tải thay vì cố gắng gọi nội dung từ bên ngoài một cách rõ ràng.

function B = subsref(A, S) 
    % Handle the first indexing on your obj itself 
    switch S(1).type 
     case '()' 
      B = % ... do your custom "()" behavior ... 
     otherwise 
      % Enable normal "." and "{}" behavior 
      B = builtin('subsref', A, S(1)) 
     end 
    end 
    % Handle "chaining" (not sure this part is fully correct; it is tricky) 
    orig_B = B; % hold on to a copy for debugging purposes 
    if numel(S) > 1 
     B = subsref(B, S(2:end)); % regular call, not "builtin", to support overrides 
    end 
end 

(Và nếu điều đó builtin cuộc gọi không làm việc, bạn có thể chỉ cần đặt trong các trường hợp sử dụng .{} trực tiếp, bởi vì tình trạng quá tải subsref bị bỏ qua bên trong định nghĩa lớp.)

Để làm cho nó đầy đủ chức năng, bạn có thể cần phải thay đổi B thành một varargout và thêm hành vi chuỗi vào trường hợp "()".

+0

Cảm ơn, điều này gần như hoạt động nhưng không hoàn toàn - vui lòng xem cập nhật trong câu hỏi của tôi – Ben

+0

Điều gì đang diễn ra ở đó là trong Matlab, một biểu thức có nhiều chỉ mục như 'foo.bar.baz (3)', thay vì được đánh giá các bước như thực hiện 'foo.bar' và sau đó chuyển kết quả tới' .baz' và sau đó chuyển kết quả đó tới '(3)', sẽ phân tích cú pháp toàn bộ biểu thức và truyền nó trong một cuộc gọi duy nhất tới subsref. Vì vậy, 'subsref' của bạn cần xem xét S, xử lý S (1), và sau đó xử lý hành vi" chuỗi "bằng cách tự chuyển kết quả cùng với' S (2: end) 'cùng với một cuộc gọi khác 'subsref', sau đó sẽ nhận phương thức quá tải. –

+0

Tôi đã sửa đổi mã ví dụ của mình để hiển thị hành vi "chuỗi". Đó là một chút khó khăn và tôi không thể kiểm tra nó cho sự chính xác bởi vì tôi không có Matlab ngay bây giờ (xin lỗi), nhưng điều này về cơ bản là những gì bạn cần làm. –

0

Nói chung. Bạn nên sử dụng builtin(m,s) bên trong hàm bị quá tải. Điều này được quy định rõ ràng trong tài liệu MATLAB.

http://www.mathworks.com/help/matlab/ref/builtin.html

dựng sẵn (chức năng, x1, ..., xn) thực hiện các chức năng được xây dựng trong với các đối số đầu vào x1 qua xn. Sử dụng nội trang dựng sẵn để thực thi gốc được tích hợp từ bên trong một phương thức làm quá tải hàm. Để làm việc đúng cách, bạn không bao giờ phải quá tải nội trang.

xem xét mã này:

classdef TestBuiltIn 
    properties 
     testprop = 'This is the built in method'; 
     testprop2 = 'This is the derived subsref '; 
    end 
    methods 

     function v = subsref(m, s) 
      disp('enter subsref no matter how!'); 
      v = builtin('subsref',m, s); 
     end 
    end 
end 

và kiểm tra lệnh

clear; 
t = TestBuiltIn; 
builtin('subsref', t, s) 
s.type = '.'; 
s.subs = 'testprop'; 
s2 = s; 
s2.subs = 'testprop2'; 

>> builtin('subsref', t, s1) 

enter subsref no matter how! 

ans = 

This is the derived subsref 

>> builtin('subsref', t, s) 
enter subsref no matter how! 

ans = 

This is the built in method 
1

Mở rộng trên giải thích được trên Mathworks board, được xây dựng chỉ hoạt động từ bên trong một phương pháp quá tải để truy cập trước phương thức hiện có (được xây dựng).

Việc tải quá nhiều phương thức trong Matlab có hiệu quả đổ bóng việc triển khai được xây dựng từ mọi thứ ngoại trừ phương pháp làm bóng và phương pháp làm bóng phải sử dụng nội dung sẵn có để truy cập cài đặt được triển khai thay vì đệ quy vào chính nó.

0

Trong phiên bản cập nhật của sự cố này, khi bạn gọi t.child(1), chức năng subsref sẽ nhận được đối số s với s(1).type='.', s(1).subs='child's(2).type='()', s(2).subs='1'. Việc đánh giá biểu thức này không theo cách từng bước, như được nêu trong câu trả lời của anh ta. Do đó, khi ghi đè subsref, bạn nên xử lý chuỗi hoạt động này, trước tiên hãy xử lý '.' nhà điều hành. Dưới đây là một ví dụ đầy đủ cho trường hợp của bạn,

function v = subsref(this, s) 
    switch s(1).type 
     case '.' 
      member = s(1).subs; 
      if ismethod(this, member) 
       % invoke builtin function to access method member 
       % there is issue about the number of output arguments 
       v = builtin('subsref',this,s); 
      elseif isprop(this, member) % property 
       if length(s) == 1 
        % invoke builtin function to access method member 
        v = builtin('subsref', this, s); 
       elseif length(s) == 2 && strcmp(s(2).type,'()') 
        % this is where you evaluate 'tc.child(1)' 
       else 
        % add other cases when you need, otherwise calling builtin 
       end 
      else 
       % handling error. 
      end 
     case '()' 
      % this is where you evaluate 't(1)' 
      % you may need to handle something like 't(1).prop1', like the '.' case 
     otherwise 
      % by default, calling the builtin. 
    end 
end 

Bạn cũng có thể tìm thấy một mẫu mã chi tiết và hướng dẫn tại Code Patterns for subsref and subsasgn Methods.

Một điều nữa bạn có thể cần biết là các thành viên phương pháp trong lớp học này cũng sẽ được gọi thông qua subsref bằng '.' hoạt động. Hãy xem chủ đề này subsref on classes: how to dispatch methods?, bạn sẽ thấy rằng hàm builtin không có giá trị trả về (vì phương thức được gọi không có giá trị trả về). Tuy nhiên, giá trị trả về của builtin được gán cho v (mặc dù v được thay thế bằng varargout), đây là lỗi rõ ràng. Tác giả cũng đưa ra một giải pháp tạm thời bằng cách sử dụng try ... catch để giải quyết lỗi này.

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