【问题标题】:How do I default a property of a Matlab instance with a size based on an instance variable that is set upon constructing the instance?如何默认 Matlab 实例的属性,其大小基于在构造实例时设置的实例变量?
【发布时间】:2020-02-19 04:17:59
【问题描述】:

我有一个问题,我想对一些物理现象进行建模。这种现象由几个阶段组成,每个阶段都可能有自己的控制方程(动力学以及变量数量、约束、变量边界等)。为了对这个阶段的属性进行分组,我编写了一个类phase。此类的一个实例具有一个名为nVars 的属性,即控制方程中的变量数(因此在此类的实例中可能会有所不同)。

现在,假设我想要这个类的另一个属性,称为boundaries。因为我需要以非常具体的方式制定变量边界,所以我还创建了一个类boundaries。这个类有属性lowerupper;变量的下界和上界。但是,这些上下边界的长度取决于phase 实例的nVars

在最一般的情况下,下边界都是-Inf,上边界都是Inf。因此,我想将boundaries 属性lowerupper 的值分别默认为-Inf * ones([1 nVars])Inf * ones([1 nVars])。现在,我的问题是:如何使类属性的默认值依赖于变量(在这种情况下为nVars)。

我的第一次尝试:

classdef phase
    properties 
        nVars(1, 1) double
        boundaries boundaries
    end
    methods
        function obj = phase(nVars)
            %Some constructor method
            obj.nVars = nVars;
            obj.boundaries = boundaries(obj);
        end
    end
end

classdef boundaries
    properties 
        parent phase
        lower = -Inf * ones([1 parent.nVars]);
        upper = Inf * ones([1 parent.nVars]);
    end
    methods
        function obj = boundaries(parent)
            %Some constructor method
            obj.parent = parent;
        end
    end
end

或者,我尝试通过以下方式默认边界类的属性:

classdef boundaries
    properties 
        parent phase
        lower(1, parent.nVars) double = -Inf;
        upper(1, parent.nVars) double = Inf;
    end
    methods
        function obj = boundaries(parent)
            %Some constructor method
            obj.parent = parent;
        end
    end
end

谁能帮助我理解如何根据变量分配这些默认值?

【问题讨论】:

  • 或许你可以定义为lower(1,:) double = -Inf,在boundaries的构造函数中初始化为合适的大小,然后添加一个属性监听器,检查lower和@987654343的大小@ 并使用 obj.parent.nVars 验证它(仅在调用构造函数后可用)。有关属性侦听器的信息,请参阅 here
  • 您的问题的答案在您的标题中:“在构造实例时设置的变量?” ... 在 boundaries 对象的 constructor 中分配默认值。它与简单的 classdef 默认值一样好用,您可以在上面编写各种输入检查代码。

标签: matlab oop properties instance


【解决方案1】:
classdef phase < handle
    properties 
        nVars       double ;
        boundaries  boundaries ;
    end
    methods
        function obj = phase(nVars)
            %Some constructor method
            obj.nVars = nVars;
            obj.boundaries = boundaries(obj);
        end
    end
end

classdef boundaries
    properties 
        parent phase
        upper   double ;
        lower   double ;
    end
    methods
        function obj = boundaries( parent )
            % Assign the parent handle
            obj.parent = parent ;
            % Initialise default values for the properties
            obj.upper =  Inf * ones([1 parent.nVars]);
            obj.lower = -obj.upper ;
        end
    end
end

这个初始化正确:

>> a = phase(5)
a = 
  phase with properties:

         nVars: 5
    boundaries: [1x1 boundaries]
>> a.boundaries
ans = 
  boundaries with properties:

    parent: [1x1 phase]
     upper: [Inf Inf Inf Inf Inf]
     lower: [-Inf -Inf -Inf -Inf -Inf]

classdef 语法允许在属性中定义默认值,非常方便地限制必须在构造函数中完成的编码工作(自动检查输入类型和各种输入检查)。

但是,对于您在属性块中定义的每个默认值,MATLAB 都会将自动生成的代码添加到对象的构造函数中。一旦对象最终被创建和初始化,如果属性值直接在属性块或构造函数中分配,没有区别

对于您的情况,添加到构造函数的代码非常简单,因此不值得浪费时间尝试找到可在属性块中使用的语法。此外,由于另一个问题:通过引用传递,这在您的情况下总是会失败。

当您尝试为 boundaries 类中的父对象分配句柄时,您只是发送了初始阶段对象的副本。此副本将位于 boundaries 对象中,但与实际的 phase 父对象分离。为了能够通过引用传递父对象,您需要将handle 传递给该父对象,为此您需要将父类定义为handle

【讨论】:

  • 感谢您的详尽回答。的确,答案是如此微不足道,以至于我忽略了它。遗憾的是,我更喜欢默认语法,因为很明显,在检查问题时这些值会立即默认。在构造函数中拥有默认值需要读者进行更多搜索。感谢您对handle 课程的补充。你是说让 phase 类继承自 handle 并保持其余代码不变应该给我我正在寻找的行为?
  • 不完全是,从handle 继承phase 类对于boundaries 类能够保持对其父类的有效引用是必要的。您只能持有对句柄类的引用,而不是对值类的引用。但这与为属性选择的初始化方法无关。
  • 是的,我的表述不清楚。确实,我的意思是通过“我正在寻找的行为”从一个类到另一个类的有效引用。再次感谢!
猜你喜欢
  • 2021-11-03
  • 2014-10-25
  • 1970-01-01
  • 1970-01-01
  • 2016-06-19
  • 2013-02-23
  • 2010-10-24
  • 2010-10-17
  • 1970-01-01
相关资源
最近更新 更多