覆盖MATLAB中子类中的超类属性集方法

时间:2013-12-29 06:12:31

标签: matlab oop subclass superclass accessor

我有一个名为super的MATLAB类:

classdef super < handle

    properties
        aString = '';
    end

    methods
        function obj = super(obj, value)
            obj.aString = value;
        end

        function set.aString(obj, value)
            obj.aString = value;
        end
    end
end

我想覆盖从'super'派生的子类中的set函数:

classdef sub < super

    %// Property 'aString' is inherited from super

    methods
        function obj = sub(obj, value)
            %// Must include call to super constructor otherwise MATLAB will by
            %// default call constructor with no arguments but my super class
            %// requires one argument in constructor. This call should probably
            %// super set method. But I don't care.
            obj = obj@super('');

            %// Now that super constructor has returned, call sub overriding
            %// set method
            obj.aString = value;

        end

        function set.aString(obj, value)
            obj.aString = value;
        end
    end
end

上面的代码给出了以下错误:

> Cannot define property 'aString' in class 'sub' because the property
> has already been defined in the superclass 'super'

将属性定义添加到'sub'会导致相同的错误。

我也尝试使用“Abstract”作为解决方法,但我没有成功,我定义了一个Abstract类:

classdef (Abstract) bloat < handle
    properties (Abstract)
        aString
    end
end

然后尝试将'super'作为'膨胀'的孩子实施:

classdef super < bloat
%// Remainder of super code remains the same

我认为'sub'继承的时间不行,'aString'是“具体的”。然后,除了上述修改之外,我还尝试修改'sub'以在其类定义中包含'boat':

classdef sub < super & bloat
%// Remainder of super code remains the same

这也行不通。

我一直找不到任何特别说明的MATLAB文档:“你不能修改set和get方法”。

我希望我的语法不正确,但是从搜索开始我现在担心MATLAB不允许这样做(无论是作为错误还是设计)。

编辑: 我正在使用MATLAB 2013a

谢谢

3 个答案:

答案 0 :(得分:3)

另一个解决方案是使set方法调用一个受保护的函数来执行赋值时需要的任何逻辑。这个受保护的方法当然可以在子类中重写。

虽然与上面的问题无关,但总是最好有一个接受零参数的构造函数以及当前的构造函数。看看我在这方面做出的改变。

super.m

classdef super < handle
    properties
        x = 1;    % some property with a default value
    end

    methods
        function obj = super(value)
            % allow for zero-argument construction
            if nargin > 0
                obj.x = value;
            end
        end
        function set.x(obj, value)
            % call another function to check the value as desired,
            % and possibly even update it using some computation
            value = checkX(obj, value);

            % set set the property using the validated value
            % (only place we do assignment to avoid infinite recursion)
            obj.x = value;
        end
    end

    methods (Access = protected)
        function value = checkX(obj, value)
            % for example, we require that values be scalar positive
            validateattributes(value, {'numeric'}, {'scalar','positive'});
        end
    end
end

sub.m

classdef sub < super
    methods
        function obj = sub(value)
            % set inherited property if requested
            if nargin > 0
                obj.x = value;
            end
        end
    end

    methods (Access = protected)
        function value = checkX(obj, value)
            % we could call superclass method to combine effect
            value = checkX@super(obj, value);

            % or override super-class logic (example: maximum value of 10)
            value = min(value,10);
        end
    end
end

答案 1 :(得分:2)

您必须让set方法调用另一种方法,然后才能重载。这要求您使aString依赖,并将其值存储在其他位置以避免无限递归。

classdef super < handle

    properties (Dependent)
        aString
    end
    properties (Hidden)
        storeAString = '';
    end

    methods
        function obj = super(obj, value)
            obj.aString = value;
        end

        function set.aString(obj, value)
            setString(obj,value);
        end
        function value = get.aString(obj)
            value = obj.storeAString;
        end
    end
    methods (Hidden)
        function setString(obj,value)
            %# this is the method you will be able to overload
            obj.storeAString = value;
        end
    end
end

答案 2 :(得分:2)

首先,因为问题包括对Matlab文档的引用请求:

关于Property Access Methods州的Matlab文档(目前针对rev.2015a):

  

您只能定义属性访问方法:

     
      
  • 对于具体属性(即非抽象属性)
  •   
  • 在定义属性的类中(除非该属性在该类中是抽象的,在这种情况下,具体子类必须定义访问方法)。
  •   

所以看起来覆盖get / set-methods是不可能的。

第二次,这是另一个古怪的解决方法:可以创建一个属性observable,并且在通知程序中更改值。所以在超类中我们设置了SetObservable标志:

<强> super.m:

classdef super < handle

  properties (SetObservable)
      aString;
  end

  methods
    function obj = super(value)
        obj.aString = value;
    end

    function set.aString(obj, value)
        obj.aString = value;
    end
  end
end

在子类中,构造函数中引入了一个侦听器。它指向在分配属性值时调用的函数。然后,该函数检查该值(并在必要时更正/更改它)。

<强> sub.m:

classdef sub < super

    %// Property 'aString' is inherited from super

    methods
        function obj = sub(value)
            %// Must include call to super constructor otherwise MATLAB will by
            %// default call constructor with no arguments but my super class
            %// requires one argument in constructor. This call should probably
            %// super set method. But I don't care.
            obj = obj@super('');

            %// Now that super constructor has returned, call sub overriding
            %// set method
            obj.aString = value;
            addlistener(obj, 'aString', 'PostSet',@obj.checkAString);
        end
        function checkAString(self, ~, ~)
            if isempty(self.aString)
                self.aString = 'was empty';
            end;
        end
    end
end

如果你再运行

a_sub = sub('');
a_sub.aString = ''

你会得到:

a_sub = 

  sub with properties:

    aString: 'was empty'
结果是

然而,这也不是一个理想的解决方案。至少有这些缺点:

  • 监听器的输入与设置例程的输入不同。所以,如果,f.ex。原始值被覆盖,原始值不再可用(好的,可以有一个aString_backup变量,然后存储在GetObservable事件中,但这会变得更加复杂)。
  • 我认为调用侦听器的顺序可以是随机的。因此,如果一个人有多个监听器,则不确定它们中的哪一个先运行。
  • 我想在经常读/写的属性上使用侦听器时会有性能损失