MATLAB重载subsref触发无限递归的原因及修复方案咨询
MATLAB subsref重载无限递归问题分析与修复
问题代码
Dog.m
% Dog.m ------------------------------------------------- classdef Dog methods function varargout = subsref(obj, x) varargout = subsref_overloaded(obj, x); end end end
subsref_overloaded.m
% subsref_overloaded.m ---------------------------------- function varargout = subsref_overloaded(obj, x) [varargout{1:nargout}] = builtin('subsref', obj, x); end
执行错误
执行d=Dog()后调用d(),触发无限递归错误:
Maximum recursion limit of 500 reached. Error in Dog (line 2) [varargout{1:nargout}] = builtin('subsref', obj, x); Caused by: Maximum recursion limit of 500 reached.
核心疑问
代码参考MATLAB官方示例,调试发现:在Dog.m中直接调用builtin('subsref', obj, x)可正常运行,但把该逻辑封装到subsref_overloaded.m中调用就触发无限递归。请问问题原因是什么?如何修复?
背景:原本按Stack Overflow方案重载subsref,为复用逻辑,希望封装成subsref_overloaded(obj, x, fn)形式,返回fn(x)结果。
原因分析
问题出在**builtin('subsref')的调用上下文差异**:
- 在类的
subsref方法内部调用builtin('subsref', obj, x)时,MATLAB会直接跳过当前类的重载逻辑,调用原生下标引用行为。 - 但在外部独立函数
subsref_overloaded中调用builtin('subsref', obj, x)时,MATLAB的方法调度机制依然会优先触发obj所属类(Dog)的重载subsref方法,而非原生逻辑。这就形成了循环调用链:Dog.subsref→subsref_overloaded→builtin('subsref')→Dog.subsref,最终触发无限递归。
修复方案
要在外部函数中正确调用原生subsref逻辑,需要绕开子类的方法调度,直接调用对象基类的原生subsref方法。
基础修复版(适配现有代码)
修改subsref_overloaded.m,通过对象的基类调用原生逻辑:
% subsref_overloaded.m ---------------------------------- function varargout = subsref_overloaded(obj, x) % 获取对象的基类(handle类基类为handle,值类基类为matlab.mixin.Heterogeneous) base_class = metaclass(obj).SuperclassList(1).Name; % 调用基类的原生subsref方法 [varargout{1:nargout}] = feval(base_class, 'subsref', obj, x); end
增强版(支持传入处理函数fn)
针对你希望复用逻辑的需求,实现subsref_overloaded(obj, x, fn)形式,先获取原生结果再传入函数处理:
% subsref_overloaded.m ---------------------------------- function varargout = subsref_overloaded(obj, x, fn) % 调用基类原生subsref获取基础结果 base_class = metaclass(obj).SuperclassList(1).Name; [res{1:nargout}] = feval(base_class, 'subsref', obj, x); % 若传入处理函数,对结果进行加工 if nargin >= 3 && isa(fn, 'function_handle') varargout = cellfun(fn, res, 'UniformOutput', false); else varargout = res; end end
验证效果
修改后执行d=Dog(); d(),将不再触发递归,能正常执行原生下标引用逻辑(若类未定义其他方法,会触发默认的对象显示行为)。
内容的提问来源于stack exchange,提问作者OverLordGoldDragon
相关产品推荐
相关产品推荐

