2013-04-24 86 views
6

我想只爲一個特定的類重載一種subsref調用('()'類型),並留下任何其他調用Matlab的內置子參考 - 具體來說,我希望Matlab通過處理屬性/方法訪問''類型。但是,當subsref在類中被重載時,似乎Matlab的'builtin'函數不起作用。爲什麼我不能使用內建函數來重載subsref?

考慮這個類:

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 

要使用重載的subsref方法,我這樣做:

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

這是符合市場預期。但是現在我想調用Matlab內置的subsref方法。爲了確保我正確地做事,我首先嚐試了類似的結構調用:

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

這也如預期的那樣。但是,當我嘗試在TestBuiltIn同樣的方法:

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

... MATLAB調用重載的方法,而不是內置的方法。爲什麼Matlab在調用內置的方法時調用超載的方法?

更新: 對@Andrew Janke的回答,該解決方案几乎可行但不完全。考慮這個類:

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 = TestIndexing; 
t(1) 
    >> overloaded method 
t.prop1 
    >> 1 
t.child 
    >> [TestIndexing instance] 
t.child.prop1 
    >> 2 

但是,這並不正常工作;它使用內置的subsref爲孩子而不是超載的subsref:

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

注意上面的行爲與這兩種行爲(這是如預期)的不一致:

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

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

不知道我是否完全理解,但我認爲首先調用內置函數,然後在該調用中調用重載方法。如果可能的話,在有用點放置一個斷點。 – 2013-04-24 18:40:17

+0

完全不同的東西:我希望你只是爲了個人興趣去嘗試這樣做,因爲對於大多數問題,重載subsref可能不是最好的解決方案。 – 2013-04-24 18:41:39

+0

我不確定你首先調用的內建函數是什麼意思 - 如果這是假設的情況(不知道如何,但說),我想我需要在Matlab的內置subsref函數內設置一個斷點來驗證。但是,這是一個本地函數,而不是一個m函數,所以我不能在那裏放置一個斷點。 – Ben 2013-04-24 19:26:07

回答

4

這是可能的,IIRC。要更改()而不是{}和'。',請編寫您的subsref方法,以將其他情況從您的重載子參考內傳遞到內置子參考,而不是嘗試從外部顯式調用內建。

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 

(如果這builtin不能正常工作,你可以把在直接使用.{}情況下,由於subsref過載的類定義中忽略)。

要使它功能齊全,您可能需要將B更改爲可變參數,並將鏈接行爲添加到「()」情況中。

+0

謝謝,這幾乎工作,但不完全 - 請參閱我的問題 – Ben 2013-04-24 21:43:23

+0

更新什麼是在Matlab,一個表達式與多個索引像'foo.bar.baz(3)',而不是被評估如執行'foo.bar',然後將結果傳遞給'.baz',然後將結果傳遞給'(3)',將解析整個表達式並將其傳遞給subsref。 (這是不直觀的。)所以你的'subsref'需要看S,處理S(1),然後通過手工將結果與'S(2:end)'一起傳遞給另一個調用來處理「鏈接」行爲'subsref',然後它會選擇重載的方法。 – 2013-04-25 00:01:17

+0

我修改了示例代碼以顯示「鏈接」行爲。這有點棘手,我無法測試它的正確性,因爲我現在沒有Matlab(對不起),但這基本上是你需要做的。 – 2013-04-25 00:05:54

0

一般來說。你應該在被重載的函數中使用builtin(m,s)。這在MATLAB文檔中有明確的說明。

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

內建(函數,X 1,...,xn)映射執行與通過所述XN輸入 參數X1的內建函數。使用內置函數在重載函數的方法中執行內置的原始 。爲了正確工作 ,您絕不能超載內建函數。

考慮以下代碼:

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 

和測試命令

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

要上的Mathworks board給出的解釋擴展,內置只能從工作的重載的方法來訪問內前現有(內置)方法。

重載在Matlab的方法有效地屏蔽了該建在執行從一切除了方法做了陰影,並做了陰影的方法必須使用內置的訪問內置的執行,而不是在遞歸到自身。

0

在這個問題的更新後的版本,當你調用t.child(1),該subsref函數將收到的參數ss(1).type='.', s(1).subs='child's(2).type='()', s(2).subs='1'。這個表達式的評估並沒有按照他的回答中提到的Andrew Janke一步一步的方式。因此,在覆蓋subsref時,您應該先處理'。',然後處理該操作鏈。運營商。下面是一個不完整的例子對於你的情況,

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 

您還可以找到在Code Patterns for subsref and subsasgn Methods了詳細的代碼示例和指令。

還有一件事你需要知道的是,在這個類方法成員也將通過與subsref調用「」操作。看看這個主題subsref on classes: how to dispatch methods?,你會發現builtin函數沒有返回值(因爲被調用的方法沒有返回值)。但是,builtin的返回值分配給v(即使vvarargout取代),這是一個明顯的錯誤。作者還通過使用try ... catch來解決此錯誤提供了一個臨時解決方案。

相關問題