MATLAB - 创建变量的引用(句柄?)

时间:2011-08-16 21:59:27

标签: matlab oop matlab-class

假设我有以下课程:

classdef myClass < handle
    properties
        A = 1
    end
    methods
        function obj = myClass(val)
            obj.A = val;
        end
    end
end

假设我实例化了这个类的一个实例,然后稍微操作它然后复制它。由于它是一个句柄类,“副本”实际上只是相同对象的另一个实例:

>> q = myClass(10);
>> q.A = 15;
>> w = q;
>> disp(w.A)
   15

但是我想看A而不需要实例化myClass。天真地做着

>> value = w.A

不起作用,因为这只是复制值;稍后改变w.A不会改变value

有没有办法向w.A提供“指针”或“引用”而无需创建单独的句柄类?我宁愿保留符号w.A而不是w.A.value(我必须创建句柄类以包含该值)。

编辑:我正在使用此功能以帮助封装我的代码以供我的研究实验室使用。我正在设计MATLAB和Arduino之间的接口来控制空中和地面车辆;我希望能够访问“vehicle.pwmMax”,“vehicle.flightCeiling”等内容来封装基础对象:“vehicle.Globals.pwmMax.value”等。

3 个答案:

答案 0 :(得分:16)

您可以使用PropertyReference类

来完成此操作
classdef PropertyReference < handle
    %PropertyReference Reference to a property in another object    
    properties
        sourceHandle
        sourceFieldName
    end

    properties (Dependent = true)
         Value
    end

    methods                
        function obj = PropertyReference (source, fieldName)            
            obj.sourceHandle = source;
            obj.sourceFieldName = fieldName
        end
        function value = get.Value( obj )
            value = obj.sourceHandle.(obj.sourceFieldName);
        end

        function set.Value( obj, value )
            obj.sourceHandle.(obj.sourceFieldName) = value;
        end
        function disp( obj )
            disp(obj.Value);
        end
    end              
end

继续您的示例,您可以按如下方式使用PropertyReference:

q = myClass(10);
>> q.A = 15;
>> ref = PropertyReference(q,'A');
>> disp(ref)
   15
>> q.A = 42;
>> disp(ref)
   42

使用PropertyReference类有点尴尬,但原始类保持不变。

编辑 - 根据strictrude27评论添加了disp函数重载

答案 1 :(得分:5)

考虑到你所有的限制条件,我认为没有任何东西能完全符合你的要求。

但是,我对你的符号问题并不十分清楚。当您考虑w.A没有改变时,为什么要保留符号value?保持符号w.A相似并不是一个真正的问题。

使用一些修改过的代码,我可以产生以下执行:

>> q = myClass(10);
>> q.A = 15;
>> w = q;
>> w.A
    15
>> value = w.Aref;
>> value()
    15
>> w.A = 20;
>> value()
ans =
    20

但是没有办法围绕符号value(),因为这是实施的转折点;我认为是最接近你想要的东西。当您使用以下代码实现myClass时,您将获得上述行为:

classdef myClass < handle
properties
    A = 1;
end
methods
    function obj = myClass(val)
        obj.A = val;
    end
    function a = Aref(obj)
        a =  @()(obj.A);
    end
end
end

所以你看到Aref方法实际上返回一个从对象中获取值的函数句柄。这也意味着此引用是只读的!

另请注意,在能够获得myClass的值之前,您必须实例化A实例(否则,从哪里获得A的值?)。此实例不必在当前工作空间(例如另一个函数范围)内可见,因为myClass实例存储在函数句柄value中。

这个方法的缺点是你只得到一个只读引用,你将不得不使用调用value()来获取实际值而不是函数句柄(这样就改变了符号,但不是你希望保留一个(或者至少可以通过A替换我的代码中的Aval并将Aref重命名为A来实现。另一个缺点是解决问题value可能比简单地解析一个变量慢一点(这是否会影响你value()的用法)。

如果您想要更改某些符号,可以使用dependent属性来完成:

classdef myClass < handle
    properties (Access=private)
        Aval = 1;
    end
    properties (Dependent)
        A;
    end
    methods
        function obj = myClass(val)
            obj.A = val;
        end
        function a = get.A(obj)
            a =  @()(obj.Aval);
        end
        function set.A(obj,value)
            obj.Aval = value;
        end
    end
end

上述等效执行由下式给出:

>> q = myClass(10);
>> q.A = 15;
>> w = q;
>> w.A()
    15
>> value = w.A;
>> value()
    15
>> w.A = 20;
>> value()
ans =
    20

编辑我想到了另一种方法来实现这一点,这更简单(即只保留原始帖子的类),但它要求您更改其他地方的代码。它背后的基本思想与第一个相同,但没有将它封装在对象本身(这使得对象更清晰,恕我直言)。

>> q = myClass(10);
>> q.A = 15;
>> w = q;
>> w.A()
    15
>> value = @()(w.A);
>> value()
    15
>> w.A = 20;
>> value()
ans =
    20

答案 2 :(得分:2)

由于您使用的是handle class,因此示例中的qw都会引用内存中的相同对象;它们本身就是它们所代表的对象的“指针”/“参考”。

继续你的例子,如果你改变一个,它将反映在另一个。

>> q = myClass(10);
>> w = q;
>> q.A = 99;
>> disp(w.A)
    99

另请注意,在致电w = q;时,您不会创建该课程的其他实例。在内存空间方面比较以下示例:

>> q = myClass(rand(7000));
>> m = memory; disp(m.MemUsedMATLAB)
   792870912
>> w = q;
>> m = memory; disp(m.MemUsedMATLAB)
   792834048

反对:

>> q = myClass(rand(7000));
>> w = myClass(rand(7000));
??? Error using ==> rand
Out of memory. Type HELP MEMORY for your options.

修改

玩弄这个,我提出了以下的hackish解决方案。

首先,我们围绕类构造函数创建一个包装器函数。它像往常一样创建一个对象,并且它返回一个函数句柄,该函数句柄充当与使用“PostSet”事件监听器与原始对象属性同步的闭包变量的只读访问器。

对原始类的唯一更改是添加SetObservable属性属性:

myClass.m

classdef myClass < handle
    properties (SetObservable)
        A
    end
    methods
        function obj = myClass(val)
            obj.A = val;
        end
    end
end

myClassWrapper.m

function [w A] = myClassWrapper(varargin)
    w = myClass(varargin{:});
    A = @getWA;

    %# closure variable
    a = w.A;

    %# add listener to when w.A changes
    addlistener(w, 'A', 'PostSet',@changeCallback);

    function val = getWA()
        %# return the value of the closure variable
        val = a;
    end
    function changeCallback(obj,ev)
        %# update the closure variable
        a = ev.AffectedObject.A;
        %#fprintf('Value Changed to %g\n',a)
    end
end

现在我们可以将包装器用作:

>> [w a] = myClassWrapper(10);
>> a()
ans =
    10
>> w.A = 99;
>> a()
ans =
    99