9

假设我有以下课程:

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”等。

4

3 回答 3

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 函数重载

于 2011-08-17T00:01:48.847 回答
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并重命名ArefA) 来实现。另一个缺点是解析value可能比简单地解析变量要慢一些(这是否是一个问题取决于您对 的使用value())。

如果您想更改某些符号,可以通过使用相关属性来完成:

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
于 2011-08-17T00:03:40.380 回答
2

由于您正在使用句柄类,因此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.

编辑

玩弄这个,我想出了以下骇人听闻的解决方案。

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

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

我的班级.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
于 2011-08-16T22:25:26.350 回答