6

我想为特定类仅重载一种类型的 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 而不是重载的 subsref:

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

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

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

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

4 回答 4

4

这是可能的,IIRC。要更改()但不更改{}“。”,请编写您的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调用不起作用,您可以直接放入使用.and的情况{},因为subsref在类定义中忽略了重载。)

为了使其功能齐全,您可能需要将 B 更改为 varargout,并将链接行为添加到“()”案例中。

于 2013-04-24T20:40:14.977 回答
1

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

在 Matlab 中重载方法有效地将内置实现从除执行遮蔽的方法之外的所有内容中遮蔽,并且执行遮蔽的方法必须使用 builtin 来访问内置实现而不是递归到自身。

于 2013-04-24T21:56:20.627 回答
0

一般来说。您应该builtin(m,s)在被重载的函数内部使用。这在 MATLAB 文档中有明确规定。

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

builtin(function,x1,...,xn) 使用输入参数 x1 到 xn 执行内置函数。使用 builtin 从重载函数的方法中执行原始内置。为了正常工作,你绝不能重载内置。

考虑这段代码:

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
于 2013-04-24T20:49:44.100 回答
0

在此问题的更新版本中,当您调用 时t.child(1),该subsref函数将接收s带有s(1).type='.', s(1).subs='child'and的参数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

您还可以在代码模式中找到关于 subsref 和 subsasgn 方法的详细代码示例和说明。

您可能需要知道的另一件事是,此类中的方法成员也将通过subsref'.'调用。手术。看看这个关于类的主题 subsref:如何调度方法?,你会发现builtin函数没有返回值(因为调用的方法没有返回值)。但是, 的返回值builtin被赋值给v(即使v被替换为varargout),这是一个明显的错误。作者还给出了一个临时解决方案,通过使用try ... catch来解决这个错误。

于 2017-08-03T02:21:44.133 回答