Search code examples
matlaboperator-overloadingoverloadingoverload-resolutionmatlab-class

How to overload A{n} in a custom class? matlab 2020a


Background knowledge

subsref

Some explanations in the book (published in 2014): When overloading the subsref method, you can use a switch statement to select the type of index and obtain the actual index value. The following three code snippets illustrate how to handle the input parameters. In each case, the function must return a value, which is the result of the indexing. Parentheses indexing, operation %Parentheses indexing, operation:A(n)

switch S.type case '()' B = A(S.subs{:}); end

Brace indexing, operation

%Brace indexing, operation:A{n}
switch S.type
    case '{}'
       B = A.CellProperty{S.subs{:}};    %What is CellProperty????
end

Member indexing, operation

%Member indexing, operation:A.name1
    switch S.type
    case '.'
       switch S.subs
       case 'name1'
          B = A.name1;
       case 'name2'
          B = A.name2;
       end
    end

The other two pieces of code are easy to understand, but Brace indexing is a bit confusing. What is .CellProperty? Why can't we use B = A{S.subs{:}}? To clarify this issue, I conducted an experiment in the following example code, hoping to achieve an overload for p{2}.


Example Code line34 is key point

    classdef  MPolynom
    properties
        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 '()'          %圆括号类型的引用 This is the key point You can set a program breakpoint here
                    ind = s.subs{:};
                    b = polyval(a.coef,ind);  %返回多项式的值 This is the key point
                case '.'         %“.”类型的引用
                    switch s(1).subs
                        case 'coef'
                            b = a.coef;
                        case 'plot'     %由于方法plot没有返回值,这里单独列出访问过程
                            a.plot;
                        otherwise        %其他带返回值方法的引用
                            if length(s)>1
                                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

Running the following code will yield the correct result

p=MPolynom([1,3,2,5]);
p(2)
ans =
    29

Next, I will attempt to implement P{2} I wish ans=29, I will try modifying lines 35 to 36 of the Example Code This approach has an error; I cannot add breakpoints p=MPolynom([1,3,2,5]); cannot be executed

 classdef  MPolynom
    properties
        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 = a.{s.subs{:}};
                    b = polyval(a.coef,ind);  %返回多项式的值
                case '.'         %“.”类型的引用
                    switch s(1).subs
                        case 'coef'
                            b = a.coef;
                        case 'plot'     %由于方法plot没有返回值,这里单独列出访问过程
                            a.plot;
                        otherwise        %其他带返回值方法的引用
                            if length(s)>1
                                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

Another approach p=MPolynom([1,3,2,5]); can be executed But when executing p{2}
the program throws an error at line 36, 'Unrecognized method, property, or field 'CellProperty' of class 'MPolynom'. Error in MPolynom/subsref (line 36) ind = a.CellProperty{s.subs{:}};

So, how should we implement an overload for p{2}?

classdef  MPolynom
    properties
        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 = a.CellProperty{s.subs{:}};
                    b = polyval(a.coef,ind);  %返回多项式的值
                case '.'         %“.”类型的引用
                    switch s(1).subs
                        case 'coef'
                            b = a.coef;
                        case 'plot'     %由于方法plot没有返回值,这里单独列出访问过程
                            a.plot;
                        otherwise        %其他带返回值方法的引用
                            if length(s)>1
                                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

Solution

  • Although I'm still not entirely clear about the meaning of the following code segment (I feel like it's misleading), I have successfully modified lines 35 and 36 of the Example Code to achieve overloading of {}.

    %Brace indexing, operation:A{n}
    switch S.type
        case '{}'
           B = A.CellProperty{S.subs{:}};    %What is CellProperty????
    end
    

    The modified Example Code

    classdef  MPolynom
        properties
            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{:};
                        b = polyval(a.coef,ind);  %返回多项式的值
                    case '.'         %“.”类型的引用
                        switch s(1).subs
                            case 'coef'
                                b = a.coef;
                            case 'plot'     %由于方法plot没有返回值,这里单独列出访问过程
                                a.plot;
                            otherwise        %其他带返回值方法的引用
                                if length(s)>1
                                    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
    

    The execution result

    p=MPolynom([1,3,2,5]);
    p{2}
    ans =
    
        29