15

有没有办法在 MATLAB 类中定义静态成员变量?

这不起作用:

classdef A

    properties ( Static )
        m = 0;
    end
end

建议使用关键字“Constant”而不是“Static”,不能修改常量属性。我想要一个类的所有对象共有的变量,A并且我希望能够在类的方法中修改该变量A

所以我需要的是一个私有静态成员变量。有没有办法在 MATLAB 中获得它?


发现可以使用静态成员函数中的持久变量来完成解决方法。

在这种情况下,您应该从一个基类继承所有类,如下所示。

classdef object < handle

    properties ( GetAccess = 'public', SetAccess = 'private' )
        id
    end

    methods ( Access = 'protected' )
        function obj = object()
            obj.id = object.increment();
        end
    end

    methods ( Static, Access = 'private' )
        function result = increment()
            persistent stamp;
            if isempty( stamp )
                stamp = 0;
            end
            stamp = stamp + uint32(1);
            result = stamp;
        end
    end  
end
4

4 回答 4

16

你不能,这是设计使然。您应该使用一个persistent变量(来自 MATLAB 的技术,如 1980 年在 2011 年应用的)!

为了完整起见,我应该提一下,实际上截至 2010b 存在一个未记录且可能不再受支持的static属性修饰符。

有关背景,请参见MATLAB OO 组经理Dave Foti的答案:

在 MATLAB 中,类可以定义常量属性,但不能定义其他语言(如 C++)意义上的“静态”属性。有一些测试版测试了“静态”属性,并且从那时起未记录的属性仍然存在。但是,静态属性未记录,不应使用,并且可能会在未来的 MATLAB 版本中删除。R2008a 将其实现为 Constant 的同义词,并且除了已记录的 Constant 属性行为之外不提供其他功能。

常量属性不能从属性声明中指定的初始值更改。MATLAB 的工作方式有几个原因。首先,MATLAB 有一个长期的规则,即变量总是优先于函数和类的名称,如果变量不存在,赋值语句会引入一个变量。因此,任何形式为“AB = C”的表达式都将引入一个新变量 A,它是一个结构数组,其中包含一个值为 C 的字段 B。如果“AB = C”可以引用类 A 的静态属性,则类A 将优先于变量 A,这将与 MATLAB 的先前版本非常不兼容。这意味着包含赋值语句“AB = C”的 m 文件 可以通过在 MATLAB 路径的某处引入名为 A 的类来改变其含义。MATLAB 程序员一直能够依赖赋值语句引入变量,这些变量会影响任何其他同名使用。

其次,我们观察到静态数据很少在其他类中使用,除了作为类中的私有数据或作为公共常量。例如,对几个 Java 类库的调查发现所有公共静态字段也是 final 的。在 MATLAB 中,常量属性可以像 Java 中的“public final static”字段一样使用。对于类内部的数据,MATLAB 已经具有可以在私有或受保护方法或类私有使用的局部函数内部创建的持久变量。尽可能避免在 MATLAB 中使用静态数据也是有充分理由的。如果一个类具有静态数据,则很难在多个应用程序中使用同一个类,因为静态数据可能是应用程序之间冲突的来源。在其他一些语言中,这不是一个问题,因为不同的应用程序被单独编译成在不同进程中运行的可执行文件,并具有不同的类静态数据副本。在 MATLAB 中,许多不同的应用程序可能经常在相同的进程和环境中运行,每个类只有一个副本。

于 2011-06-23T11:12:57.617 回答
11

这是在 Matlab 中创建静态属性的直接方法。此实现与假设(但不可能;参见 Mikhail 的回答)真正的静态属性之间的唯一区别是设置成员变量的语法。

classdef StaticVarClass
    methods (Static = true)
        function val = staticVar(newval)
            persistent currentval;
            if nargin >= 1
                currentval = newval;
            end
            val = currentval;
        end
    end
end

现在可以通过以下方式读取静态属性 staticVar:

StaticVarClass.staticVar

...并通过以下方式设置:

StaticVarClass.staticVar(newval);

因此,例如,这是此功能测试的预期输出:

>> StaticVarClass.staticVar
  ans =
      []
>> StaticVarClass.staticVar('foobar')
  ans =
      foobar
>> StaticVarClass.staticVar
  ans =
      foobar
>> 

这种方法同样适用于您要求的私有静态属性,但演示代码有点长。请注意,这不是句柄类(尽管它在句柄类上也可以很好地工作)。

classdef StaticVarClass
    methods (Access = private, Static = true)
        function val = staticVar(newval)
            persistent currentval;
            if nargin >= 1
                currentval = newval;
            end
            val = currentval;
        end
    end

    methods
        function this = setStatic(this, newval)
            StaticVarClass.staticVar(newval);
        end

        function v = getStatic(this)
            v = StaticVarClass.staticVar;
        end
    end
end

...和测试:

>> x = StaticVarClass
  x = 
      StaticVarClass with no properties.
      Methods
>> x.getStatic
  ans =
      []
>> x.setStatic('foobar')
  ans = 
      StaticVarClass with no properties.
      Methods
>> x.getStatic
  ans =
      foobar
>> 
于 2013-01-28T21:07:16.323 回答
1

(只是通知)有(另一种?)在matlab中创建类静态数据的方法

假设您有一个名为“car”的“句柄”类,如果您希望汽车类具有静态数据,则可以构造另一个句柄类并在汽车类抛出组合中使用它,后者类用作静态数据汽车类

classdef car<handle 
    properties 
         static_data:STATIC_DATA_HOLDER;
    end
end

classdef STATIC_DATA_HOLDER<handle
    properties
        data
    end
end

这样,当您创建汽车类的第一个实例时,将创建一个 STATIC_DATA_HOLDER 实例,而当您创建汽车类的第二个实例时,它使用先前创建的 STATIC_DATA_HOLDER 类。

这些代码使用“MATLAB 2013b”测试

于 2015-05-29T09:33:02.250 回答
0

获得静态属性之类的另一种解决方法是使用成员变量的初始化代码仅在加载类文件时执行一次这一事实。这意味着,如果您有类似的定义

classdef foo
    properties
        stuff = some_function()
    end
end

thensome_function只被调用一次,如果它返回一个类类型的对象,它将被所有实例共享。我添加了一个示例实现,展示了如何使用它:

classdef ClassWithStaticMembers
    properties
        classvars = StaticVarContainer('foo', 0, 'bar', 2);
        othervar
    end
    methods
        function obj=ClassWithStaticMembers(var)
            obj.othervar = var;
        end
    end 
end

classdef StaticVarContainer < dynamicprops
    methods
        function obj=StaticVarContainer(varargin)
            for i=1:2:numel(varargin)
                obj.addprop(varargin{i});
                obj.(varargin{i}) = varargin{i+1};
            end
        end
    end
end

如果您运行此示例代码

obj1 = ClassWithStaticMembers(3);
obj2 = ClassWithStaticMembers(5);
obj1.classvars.foo = [2,3];

obj1.othervar
obj1.classvars

obj2.othervar
obj2.classvars

你会看到,这classvars确实是共享的。我认为这个解决方案比在函数中使用持久变量要好得多,因为您可以根据StaticVarContainer需要多次重复使用,它更易于使用,此外,您可以在属性部分直接看到静态变量的初始化。

为了得到结果,在 OP 的问题(即实现对象计数器)中,可以制作共享属性Constant,以便可以在没有实例的情况下引用它:

classdef ClassWithCounter
    properties (Constant)
        static = StaticVarContainer('counter', 0);
    end
    methods
        function obj=ClassWithCounter()
            obj.static.counter = obj.static.counter + 1;
        end
    end 
end

clear all
obj1 = ClassWithCounter();
obj2 = ClassWithCounter();
obj3 = ClassWithCounter();

ClassWithCounter.static.counter

注意,该Constant属性只表示,例如obj1.static不能改变,但不影响obj1.static.counter哪个不是恒定的,可以设置为心之所想。

于 2015-11-25T16:49:20.563 回答