Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Matlab 如何调用对象';当它的一个方法被用作其自身属性的回调时,是否使用它的析构函数?_Matlab_Oop - Fatal编程技术网

Matlab 如何调用对象';当它的一个方法被用作其自身属性的回调时,是否使用它的析构函数?

Matlab 如何调用对象';当它的一个方法被用作其自身属性的回调时,是否使用它的析构函数?,matlab,oop,Matlab,Oop,我正在尝试编写一个类,该类围绕串行端口来读取传感器: classdef sensor < handle properties Value s end methods function obj = sensor(port) obj.s = serial(port); obj.s.BytesAvailableFcn = @(o,e) obj.getData;

我正在尝试编写一个类,该类围绕
串行
端口来读取传感器:

classdef sensor < handle
    properties
        Value
        s
    end

    methods
         function obj = sensor(port)
             obj.s = serial(port);
             obj.s.BytesAvailableFcn = @(o,e) obj.getData;

             fopen(obj.s);
         end
         function delete(obj)
             disp('called destructor');
             try
                 fclose(obj.s);
                 delete(obj.s);
             end
          end
          function getData(obj)
              obj.Value = fscanf(obj.s, '%d');
          end
     end
end
根据my,必须仍然有对
foo
的引用。原来这是嵌入在串行端口中的
foo.s

>> ports = instrfindall;
>> ports.BytesAvailableFcn
ans = 
    @(o,e)obj.getData
一旦我清除了
字节AvailableFcn
,即

>> ports.BytesAvailableFcn = '';
然后
清除所有
,我会显示名为析构函数的


如何打破这个循环引用并调用析构函数?如果没有调用析构函数,串行端口将保持绑定状态。

问题不在于您有一个循环引用;从理论上讲,MATLAB应该能够捕捉到这些。问题是循环引用是通过Java实现的,而MATLAB无法捕获它

更详细地说,您的
serial
对象内部包含一个Java对象,它是捕获到串行端口连接的真实对象。当您设置其回调时,MATLAB将设置底层Java对象的回调。如果回调是指向包含串行对象作为属性的对象的方法,那么就有一个通过底层Java对象的循环引用。当你调用
clear
时,MATLAB会检查循环引用,如果它们都在MATLAB中,它会捕捉它们,并调用析构函数——但它不会捕捉它们,因为它是通过Java进行的

一种解决方案是显式调用析构函数,这可能不会太麻烦

另一个解决方法可能是不将回调作为类的方法—也许它只是一个常规函数,因为除了对串行对象的引用之外,它似乎并不真正需要来自主对象本身的任何信息。如果希望将所有代码保存在一个文件中,或许可以将其创建为一个匿名函数(尽管要小心,因为匿名函数将捕获创建它的工作区,这取决于创建它的位置,可能包括对主对象的引用,在这种情况下,您将再次使用循环引用)

编辑:Rody是对的-很抱歉,我读问题的速度太快了,没有注意到
getData
实际上设置了
属性,而不仅仅是返回数据。Rody在回答中的解决方案可能是另一种解决方法,但正如他所说的-是。我只需要手动调用
delete

有趣的问题!:)

我找到了一个解决办法,但不会很好

  • 不能使用匿名函数。这将捕获本地工作区,其中将包含对
    obj
    的引用。您必须使用一个级别的间接寻址(到
    静态方法,否则,您将遇到相同的问题)
    
  • 此静态方法可以安全地返回函数句柄。此函数句柄指向一个函数,该函数必须传递给instrument对象
  • 如果不向对象传递引用,设置
    Value
    属性当然是不可能的,因此,必须在函数中创建全局状态、可变调用签名和
    Value
    属性的getter
我有一种感觉,我设计得有点过头了(毕竟现在是星期五),所以如果有人看到更简单的方法,请纠正我。总之,我的意思是:

classdef sensor < handle

    properties
        s
    end        
    properties (Dependent)
        Value
    end

    methods

        function obj = sensor(port)
            obj.s = serial(port);

            % You cannot use function handle without implicitly passing obj into 
            % it. Instead, get a function handle from another function, one that 
            % does not have this problem:
            obj.s.BytesAvailableFcn = sensor.getGetData(obj.s);                

            fopen(obj.s);
        end

        function delete(obj)
            disp('called destructor');
            try %#ok<TRYNC>
                fclose(obj.s);
                delete(obj.s);
            end
        end

        % Use a getter for Value, so that whenever you query the Value property, 
        % you get the most recently read sensor data
        function V = get.Value(obj) %#ok<MANU>
            V = getData();
        end

    end

    % Use indirection to a Static method, to avoid referencing obj implicitly
    methods (Access = private, Static)
        function f = getGetData(S)
            f = @(o,e)getData(S);
        end
    end

end

% The actual sensor reader 
function data = getData(S)

    persistent port
    if nargin == 1
        port = S; return; end

    try 
        data = fscanf(port, '%d');
    catch ME
        % ...
    end

end
classdef传感器

只是……恶心

显而易见的解决方案是显式调用
delete
方法,但我希望有更好的方法。我不知道如何在不引用对象的情况下创建函数(不依赖于某些全局状态),如果您想让它设置
属性…手动调用
删除
将是我的首选。yeesh。干得好!事实上,这带来了一个很好的观点。如果我们使用
instrfind('Type','serial','port',nameOfPort)
,并传递端口名(COM1等),而不是使用持久端口,该怎么办?然后在类构造函数中实例化一个“匿名”
serial
对象。我必须考虑一下。这样你甚至不必把
s
作为类的属性。我想知道这是否会有帮助…我猜一个持久的会有更好的表现。如果您经常阅读
,则不希望每次都搜索所有端口…从面向对象的角度来看,让类管理串行端口是有意义的,换句话说,将其作为属性。但是如果MATLAB/Java接口有问题,而这是解决方法,那么也许你的想法是
classdef sensor < handle

    properties
        s
    end        
    properties (Dependent)
        Value
    end

    methods

        function obj = sensor(port)
            obj.s = serial(port);

            % You cannot use function handle without implicitly passing obj into 
            % it. Instead, get a function handle from another function, one that 
            % does not have this problem:
            obj.s.BytesAvailableFcn = sensor.getGetData(obj.s);                

            fopen(obj.s);
        end

        function delete(obj)
            disp('called destructor');
            try %#ok<TRYNC>
                fclose(obj.s);
                delete(obj.s);
            end
        end

        % Use a getter for Value, so that whenever you query the Value property, 
        % you get the most recently read sensor data
        function V = get.Value(obj) %#ok<MANU>
            V = getData();
        end

    end

    % Use indirection to a Static method, to avoid referencing obj implicitly
    methods (Access = private, Static)
        function f = getGetData(S)
            f = @(o,e)getData(S);
        end
    end

end

% The actual sensor reader 
function data = getData(S)

    persistent port
    if nargin == 1
        port = S; return; end

    try 
        data = fscanf(port, '%d');
    catch ME
        % ...
    end

end