2013-04-24 72 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来解决此错误提供了一个临时解决方案。

相关问题