Assuming a member within a class has private access properties, i.e., GetAccess=private, if we use a "." type reference for that member in the overloaded subsref method, then the access property of that member becomes invalid at that point.
--------------------- So, is there a good way here to allow users to both retain access control for properties and overload indexing methods?
Using the builtin function cannot resolve this issue; please alternate between the code at lines 42 and 43. The fundamental reason is that setting GetAccess=private cannot prevent access within the class itself. Therefore, the code at line 42 effectively provides a backdoor for accessing object, rendering the GetAccess restriction ineffective, and this is not caused by subsref. Even if you don't use subsref, if you construct an MPolynom object within the class and assign the data from object.coef to another property, for example, object.xxx=object.coef, and then assign object.xxx externally, it can bypass the GetAccess restriction. After all, it cannot prevent class methods from accessing any class members.
classdef MPolynom
properties (SetAccess=public,GetAccess=private)
coef; %多项式系数
end
methods
function obj = MPolynom(c) %构造函数
if isa(c,'MPolynom')
obj.coef = c.coef;
else
obj.coef = c(:)';
end
end
function plot(obj) %重载plot函数
r = max(abs(roots(obj.coef)));
x = (-1.1:0.01:1.1)*r;
y = polyval(obj.coef,x);
plot(x,y);
xlabel('X')
ylabel('Y','Rotation',0)
grid on
end
function r = plus(obj1,obj2)
if ~isa(obj1,'MPolynom') %如果第一个参数不是类MPolynom对象
obj1 = MPolynom(obj1); %创建一个类MPolynom对象obj1
end
if ~isa(obj2,'MPolynom') %如果第二个参数不是类MPolynom对象
obj2 = MPolynom(obj2); %创建一个类MPolynom对象obj2
end
k = length(obj2.coef) - length(obj1.coef); %计算两个阵列的长度差
%创建一个类MPolynom对象作为返回值
r = MPolynom([zeros(1,k) obj1.coef]+[zeros(1,-k) obj2.coef]);
end
function b = subsref(a,s) %下标索引引用的实现
switch s(1).type
case '()' %圆括号类型的引用
ind = s.subs{:};
class(a.coef)
b = polyval(a.coef,ind); %返回多项式的值
case '.' %“.”类型的引用
switch s(1).subs
case 'coef'
b=builtin('subsref',a,s);
% b = a.coef;
case 'plot' %由于方法plot没有返回值,这里单独列出访问过程
a.plot;
otherwise %其他带返回值方法的引用
if length(s)>1
%b=subsref(a.coef,s);
b = a.(s(1).subs)(s(2).subs{:}); %带输入参数的方法引用
else
b = a.(s.subs); %不带输入参数的方法引用
end
end
otherwise
error('Specify value for x as obj(x)')
end
end
function y = polyval(obj,x) %计算多项式对象obj在x处的值
y = polyval(obj.coef,x);
end
end
end
Use the code on line 43 and comment out the code on line 42.
classdef MPolynom
properties (SetAccess=public,GetAccess=private)
coef; %多项式系数
end
methods
function obj = MPolynom(c) %构造函数
if isa(c,'MPolynom')
obj.coef = c.coef;
else
obj.coef = c(:)';
end
end
function plot(obj) %重载plot函数
r = max(abs(roots(obj.coef)));
x = (-1.1:0.01:1.1)*r;
y = polyval(obj.coef,x);
plot(x,y);
xlabel('X')
ylabel('Y','Rotation',0)
grid on
end
function r = plus(obj1,obj2)
if ~isa(obj1,'MPolynom') %如果第一个参数不是类MPolynom对象
obj1 = MPolynom(obj1); %创建一个类MPolynom对象obj1
end
if ~isa(obj2,'MPolynom') %如果第二个参数不是类MPolynom对象
obj2 = MPolynom(obj2); %创建一个类MPolynom对象obj2
end
k = length(obj2.coef) - length(obj1.coef); %计算两个阵列的长度差
%创建一个类MPolynom对象作为返回值
r = MPolynom([zeros(1,k) obj1.coef]+[zeros(1,-k) obj2.coef]);
end
function b = subsref(a,s) %下标索引引用的实现
switch s(1).type
case '()' %圆括号类型的引用
ind = s.subs{:};
class(a.coef)
b = polyval(a.coef,ind); %返回多项式的值
case '.' %“.”类型的引用
switch s(1).subs
case 'coef'
% b=builtin('subsref',a,s);
b = a.coef;
case 'plot' %由于方法plot没有返回值,这里单独列出访问过程
a.plot;
otherwise %其他带返回值方法的引用
if length(s)>1
%b=subsref(a.coef,s);
b = a.(s(1).subs)(s(2).subs{:}); %带输入参数的方法引用
else
b = a.(s.subs); %不带输入参数的方法引用
end
end
otherwise
error('Specify value for x as obj(x)')
end
end
function y = polyval(obj,x) %计算多项式对象obj在x处的值
y = polyval(obj.coef,x);
end
end
end
Both of the above code snippets yield the same result when executing the following command. Therefore, the effective way to enforce the GetAccess restriction is to directly use error('GetAccess=private') at line 42.
p=MPolynom([1,3,2,5]);
p.coef
It's a real shame that you're stuck on R2020a, because in R2021b there was introduced a mixin helper matlab.mixin.indexing.RedefinesParen
which is specifically designed to help you out in this case. From the reference page, here's the sort of thing you need to do:
classdef MyClass < matlab.mixin.indexing.RedefinesParen
properties (Access=public)
Label
end
methods (Access=protected)
function varargout = parenReference(obj, indexOp)
% reference
end
function obj = parenAssign(obj,indexOp,varargin)
% assignment
end
function n = parenListLength(obj,indexOp,ctx)
% instead of numel overloads
end
function obj = parenDelete(obj,indexOp)
% paren deletion
end
end
end