为什么我不能将内置用于重载subsref的类?

时间:2013-04-24 17:15:29

标签: oop matlab method-overriding built-in

我想为特定类重载一种类型的subsref调用('(')类型),并保留对Matlab内置subsref的任何其他调用 - 具体来说,我希望Matlab通过以下方式处理属性/方法访问'。'类型。但是,当在类中重载subsref时,似乎Matlab的“内置”函数不起作用。

考虑这个课程:

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:

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

请注意,上述行为与这两种行为(正如预期的那样)不一致:

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

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

4 个答案:

答案 0 :(得分:4)

可能,IIRC。要更改()但不更改{}和&#39;。&#39;,请编写您的subsref方法,将其他情况传递给您重载的subsref中的内置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更改为varargout,并将链接行为添加到&#34;()&#34;情况下。

答案 1 :(得分:1)

为了扩展Mathworks board上给出的解释,内置只能在重载方法中工作,以访问预先存在的(内置)方法。

在Matlab中重载方法有效地影响内置实现从所有除了执行阴影的方法之外,执行阴影的方法必须使用builtin来访问内置实现而不是递归到自身

答案 2 :(得分:0)

总的来说。您应该在已经过载的函数内使用builtin(m,s)。这在MATLAB文档中有明确规定。

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

  

builtin(function,x1,...,xn)执行内置函数   输入参数x1到xn。使用内置来执行原始   从重载函数的方法内置。上班   正确地说,你必须永远不要使内置过载。

考虑以下代码:

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

答案 3 :(得分: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(即使v替换为varargout),这是一个明显的错误。作者还使用try ... catch来解决此错误,从而提供了一个临时解决方案。