我想为特定类重载一种类型的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
答案 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
功能会收到带有s
和s(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
来解决此错误,从而提供了一个临时解决方案。