matlab面向对象编程入门笔记

文章目录

  • 1. 类和结构
  • 2. 定义类
  • 3. 属性
    • 3.1 private/protected/public属性
    • 3.2 constant属性
    • 3.3 hidden属性
  • 4. 方法
    • 4.1 private/protected/public方法
    • 4.2 static方法
    • 4.3 外部方法
  • 5. 动态调用
  • 6. 继承-超类
    • 6.1 handle超类
    • 6.2 dynamicprops 和 hgsetget子类
  • 7. 封闭(sealed)类、方法和属性
  • 8. 抽象(abstract)方法和属性
  • 9. Operator 重载
  • 10. 类数组
  • 11. 事件events
  • 12. mataclass 元类

matlab可以支持面向对象的编程(OOP),最近使用到了,记录一下基本的语法:

1. 类和结构

matlab可以支持类和结构体,结构体的关键字是struct,它们都可以具有属性,不过和结构体不同,我们必须预定义整个类具有哪些属性,这点和C++差不多。

另外类还多了和结构体不同的方法(对数据执行的函数)。而matlab的结构体不能定义方法。

2. 定义类

首先,创建一个与要创建的类同名的新 m 文件,并使用 classdef 关键字后跟类名为开头行。属性properties和方法methods在此行下方定义。

在方法methods我们必须包含构造函数 ,它负责构造新对象,并且它必须与类同名。构造函数可以接受任意数量的参数来指定属性的初始值,并且必须返回一个构造对象的参数。属性可以设置默认值。如果未指定默认值并且构造函数也没有对属性赋值,这些属性被赋值为空矩阵 []

   classdef date
   % write a description of the class here.
       properties
       % define the properties of the class here, (like fields of a struct)
           minute = 0;
           hour;
           day;
           month;
           year;
       end
       methods
       % methods, including the constructor are defined in this block
           function obj = date(minute,hour,day,month,year)
           % class constructor
               if(nargin > 0)
                 obj.minute = minute;
                 obj.hour   = hour;
                 obj.day    = day;
                 obj.month  = month;
                 obj.year   = year;
               end
           end
           function obj = rollDay(obj,numdays)
               obj.day = obj.day + numdays;
           end
       end
   end

我们可以按照构造函数的格式创建对象:

d1 = date(0,3,27,2,1998);

在这里插入图片描述
如果我们没有指定任何参数地创建对象,没有默认值的属性都被赋值为了[]。

d2 = date();

在这里插入图片描述

3. 属性

3.1 private/protected/public属性

上面定义的属性是public的,也就是说,可以从类外部访问:

day = d1.day;                                 % access the day property
d1.year = 2008;

在这里插入图片描述

但有时候我们不希望用户任意修改这些属性,所以我们需要对这些属性设置访问级别,matlab力提供了private、protected和public的级别。

访问级别访问权限
public任何地方访问
private只能从类的方法和公共属性访问
protected私有的,也可以从子类访问(参考后文的子类和继承)

在属性里我们还可以进行细分GetAccessSetAccess

% 外部只读属性,不可写
properties(GetAccess = 'public', SetAccess = 'private')
    % public read access, but private write access.
end

% 外部不可读也不可写
properties(GetAccess = 'private', SetAccess = 'private')
    % private read and write access
end

3.2 constant属性

我们还可以分配Constant属性,让该属性块的属性是常量(默认是不是常量),并且不能在任何地方进行修改:

properties(Constant = true)
    DAYS_PER_YEAR =  365;
    MONTHS_PER_YEAR = 12;
    WEEKS_PER_YEAR  = 52;
end

3.3 hidden属性

另外还有Hidden,可以隐藏属性(默认是不隐藏)

properties(Hidden= true)
    DAYS_PER_YEAR =  365;
    MONTHS_PER_YEAR = 12;
    WEEKS_PER_YEAR  = 52;
end

完整的类的定义我们修改为了:

classdef date
   % write a description of the class here.
       properties (Hidden = false)
       % define the properties of the class here, (like fields of a struct)
           minute = 0;
           hour;
           day;
           month;
           year;
       end
       properties(Constant = true)
           DAYS_PER_YEAR =  365;
           MONTHS_PER_YEAR = 12;
           WEEKS_PER_YEAR  = 52;
       end
       methods
       % methods, including the constructor are defined in this block
           function obj = date(minute,hour,day,month,year)
           % class constructor
               if(nargin > 0)
                 obj.minute = minute;
                 obj.hour   = hour;
                 obj.day    = day;
                 obj.month  = month;
                 obj.year   = year;
               end
           end
           function obj = rollDay(obj,numdays)
               obj.day = obj.day + numdays;
           end
       end
end

当我们使用properties()时只能查看非隐藏的属性:

properties(date)

(隐藏了minute等属性,Hidden = true
在这里插入图片描述

(未隐藏minute等属性,Hidden = false
在这里插入图片描述

4. 方法

我们前面已经在类里定义了一个简单的方法rollDay(),前面我们已经初始化了d1:

d1 = date(0,3,27,2,1998);

我们可以使用下面两种方式进行方法的调用(大家可以自己输入命令尝试一下看属性里的day是不是发生了改变):


d1 = rollDay(d1,3); %
d1 = d1.rollDay(3);

第二种写法和C++的差不多,两种方式都是可以的,注意当我们修改任何属性的时候我们必须注意返回对象,默认情况下,Matlab 中的对象是按值传递的,而不是通过引用传递的, 这意味着对象的完整副本被传递给方法,它是已修改的此副本。如果我们不传回此副本, 有效地覆盖了原始内容,我们不会观察到任何更改。当然我们也可以选择编写对象被传递的类引用(这在后面的Handle Superclass将会介绍到)

方法也像属性一样可以有三个访问级别:private、protected或public,private方法不能用于类外部使用,把一个public的方法拆分成一系列的private的函数的调用是很有效的。

4.1 private/protected/public方法

我们通过将private、protected或public分配给Access属性定义对方法的访问,我们可以自由地创建任意数量的方法块,每个方法块都具有不同的访问属性。例如private的方法:

methods(Access = private)
   function sec = calcSecs(obj)
     sec = obj.minute*60 + obj.hour*60*60 + obj.day*24*60*60;
   end
   function TF = isValid(obj)
       TF = obj.minute >= 0 && obj.minute <= 60;
   end
end

4.2 static方法

static的方法是和类关联的方法,而不是与该类的实例相关联的方法:

 methods(Static = true)
     function printCurrentDate()
         display(datestr(now));
     end
 end

完整代码:

classdef date
   % write a description of the class here.
       properties (Hidden = false)
       % define the properties of the class here, (like fields of a struct)
           minute = 0;
           hour;
           day;
           month;
           year;
       end
       properties(Constant = true)
           DAYS_PER_YEAR =  365;
           MONTHS_PER_YEAR = 12;
           WEEKS_PER_YEAR  = 52;
       end


       methods
       % methods, including the constructor are defined in this block
           function obj = date(minute,hour,day,month,year)
           % class constructor
               if(nargin > 0)
                 obj.minute = minute;
                 obj.hour   = hour;
                 obj.day    = day;
                 obj.month  = month;
                 obj.year   = year;
               end
           end
           function obj = rollDay(obj,numdays)
               obj.day = obj.day + numdays;
           end
       end

       methods(Static = true)
           function printCurrentDate()
             display(datestr(now));
           end
       end

end

当方法和类相关的时候,但是不需要使用类实例的特定的信息的时候,我们可以设置属性为static。如果要调用static方法,我们需要指定类名,后面跟.和静态方法的名称(把前面的程序加入类里),调用的时候使用下面的语句都是可以的:

date.printCurrentDate()
d1.printCurrentDate()

方法也可以用 methods(Hidden = true) 隐藏,从显示类方法的函数(例如 methods()methodsview() )中隐藏它们。

4.3 外部方法

类的方法可以自由地调用任何在matlab路径的外部函数来实现计算,此外如果我们在与类同名的文件夹里保存classdef m文件,但文件夹的名字前面加了前缀@(如@date),我们就可以在这个文件夹把类的方法和声明类似C++的h文件和cpp文件分离开来。具体来说:

我们在当前文件夹创建@date文件夹,在里面放入文件date.m(类文件),然后我们可以把rollDay()函数放在外面编写,新建一个rollDay.m文件:
在这里插入图片描述
date.m类文件里我们改写关于rollDay()的声明:

methods
   	 obj = rollDay(obj,numdays)
end

然后在rollDay.m编写rollDay()的定义

function obj = rollDay(obj,numdays)
   obj.day = obj.day + numdays;
end

我们可以使用同样的调用的方式得到和内部定义方法一样的效果:

d1 = date(0,3,27,2,1998);
d1 = d1.rollDay(3)

但是在类文件外定义的这些方法将无法分配前面讨论的任何访问级别(static、hidden、protected),它们是自动为public的。

如果要编写外部的私有方法,需要把它保存在名为private的子目录下,例如\@date\private\rollDay.m

在这里插入图片描述

date.m我们改写rollDay()函数(改成private属性),并且加上一个rollDayCall()函数为public属性方便我们外部调用,然后我们把前面的rollDay函数移动到private文件夹下面

methods
    function obj = rollDayCall(obj, numdays)
         obj = rollDay(obj,numdays)
    end
end
methods(Access = private)
    obj = rollDay(obj,numdays)
end

我们同样可以测试一下,是可以正常运行的:

d1 = date(0,3,27,2,1998);
d1 = d1.rollDay(3)

关于这一部分的内容maltab也有相关的参考的内容:
Methods in Separate Files

5. 动态调用

OOP的一个优点是我们可以创建两个不同的类,每个类可以有相同的方法名称,matlab会自动根据传递的对象的类型调用正确的方法。例如,像 obj = increment(obj) 这样的调用将从 obj 碰巧的类调用 increment 方法,即使多个类具有 increment 方法也是如此。

当多个对象传递给一个方法时,Matlab 会根据上下关系确定要调用哪个类的方法。调用最高级类的方法,如果所有类具有相同的优越性,则最左边的对象 优先。

我们在创建类时指定这些关系,就在 classdef 语句中,如下所示:

classdef (InferiorClasses = {?ClassName1,?ClassName2}) MyClass
   ...
end

这里的? 用来构造元类metaclass实例,但是具体的细节并不是很重要(可以看matlab文档:metaclass和Class Precedence)。class1 和 class2 是 下层类inferior 的实例。我们将在后面的部分中讨论元类meta class。

类对象数组也可以传递给方法,但类对象数组的类加和对象类存储在数组里面一样(数组的所有元素必须是同一种类类型),并且此类用于确定优先级。有关更多信息,请参阅对象数组部分。

6. 继承-超类

我们经常会发现有些类是特例,比如地球是行星类的一个特定的实例,而行星是天体类的一个子类subclass。

我们可以编写子类来继承其超类superclass的所有属性和方法,这样我们就不需要重新编写所有的父类的功能,而子类只需要扩展或专门化这个功能。我们可以将子类的方法视为它自己的所有方法和其父超类的结合,属性也是这样的。

子类可以重新定义父类的方法(在子类里编写同名的方法即可,方法参数的数量和名字也不需要和父类相同):子类版本被用于子类的对象,而父类的版本被用于父类的对象(这是另一个被用于动态调用的例子)。

当前发现在为两个或更多的类编写方法时,可以考虑使用继承,让子类拥有父类的所有共同的代码。我们可以在类的classdef语句中使用下面的语法来为我们正在编写的类指定一个超类的定义:

classdef classname < superclass

classname是当前类的名字,而superclass是超类的名字,matlab也可以支持多重继承,即具有多个超类,注意不要发生命名的冲突,要使用多个类继承,我们使用&来分割超类:

classdef classname < superclass1 & superclass2 & superclass3

当方法已经在子类重新定义,有时候我们需要从子类调用超类的版本,例如希望子类版本做超类版本可以做的事,我们不需要从超类复制代码,而可以直接调用超类的版本,我们可以使用@运算符来对超类的方法和属性进行访问:

methodname@superclassname(input1, input2)

如果没有重新定义这些超类的方法,也没有必要使用@运算符来得到这些继承的方法(尽管这也不会发生错误),可以像子类的方法和属性一样直接访问这些超类的方法和属性而不用使用@运算符。

可以使用空的classdef声明创建相同类的多个别名(继承了但是没有对超类进行任何的扩展):

classdef newclassname < oldclassname
end

6.1 handle超类

前面我们已经提到matlab的对象默认情况下是值传递,即在方法中来回传递完整的副本调用,然而matlab的图形对象是通过引用传递的(通过Handle句柄),如果我们子类化内置的句柄类,如:

classdef myclass < handle

这样我们类的对象也将通过引用传递,而不是通过值传递。这样做有很多好处。当我们构造一个句柄对象时,如 h = myclass() 中,h 存储的是指向该对象的指针或句柄,而不是对象本身。如果我们随后执行 h2 = h,我们只需创建另一个指向同一基础对象的指针。例如,我们可以调用 h.prop = 3 ,然后 p = h2.prop ,我们可以得到 p = 3

在句柄方法调用中,不需要返回对象,因为分配就地发生(返回对象的句柄不会造成任何危害)。

如果我们的对象需要使用非常大的存储空间,使用handle对象可以更加节省空间,因为我们不再需要复制整个对象到每个方法调用中。

而且只有handle类可以支持evenets(事件),在后面我们会进行讨论。

使用handle类最主要的优点在于它可以更简单地写入数据结构,尤其是那些需要递归的结构(比如二叉树),这里给出一个非常简单的二叉树实现并说明如何只通过句柄轻松地递归所有节点。

在这里插入图片描述

bnode.m

classdef bnode < handle               % subclass handle
    properties
       left;        % left  child
       right;       % right child
       data;        % data stored at the node
    end
    methods
        function obj = bnode(data)
            obj;
            if(nargin > 0)
                obj.data = data;
            end
        end
    end
end

labelNodes.m(实现的是前序遍历)

function labelNodes(node)
% recursively label the depth of the nodes
    if(isempty(node))
    	return
    end
    disp(node.data);
    labelNodes(node.left);
    labelNodes(node.right);
end

我们可以编写测试代码随便生成一个二叉树:

n1 = bnode(1);
n2 = bnode(2);
n1.left = n2;
n3 = bnode(3);
n2.left = n3;
n4 = bnode(4);
n2.right = n4;

然后测试一下前序遍历二叉树:

labelNodes(n1)

在这里插入图片描述

创建句柄对象的相同副本则要复杂得多,因为我们不能简单地转到 h2 = h1。但是,我们可以使用以下代码来创建任何对象的浅拷贝。它需要完全访问所有属性等所以需要被添加为一个类的方法。另一种方法是使用 struct() 函数将对象转换为结构体,然后编写构造函数以选择性地采用结构体,构建一个新对象。

function copy = copyobj(obj)
% Create a shallow copy of the calling object.
    copy = eval(class(obj));
    meta = eval(['?',class(obj)]);
    for p = 1: size(meta.Properties,1)
        pname = meta.Properties{p}.Name;
        try
            eval(['copy.',pname,' = obj.',pname,';']);
        catch
            fprintf(['\nCould not copy ',pname,'.\n']);
        end
    end
end

拷贝的使用直接调用函数就可以了,例如:

copy = copyobj(n1)% n1是前面定义的二叉树的结点

当堆栈上没有剩余对象的句柄时,该对象将被声明为无效,并且 Matlab 垃圾回收器当有机会时会释放内存。我们可以使用 isvalid(h) 方法测试对象的句柄是否有效并使用 delete(h)删除该对象,使其所有句柄变得无效。

6.2 dynamicprops 和 hgsetget子类

handle有两个子类分别为dynamicprops 和 hgsetget,可以对它们继续进行子类化,而产生其他功能。

通过子类化dynamicprops,可以无需修改类的定义而将附加动态属性到对象上,我们只需要调用继承的addprop()函数,如p=obj.addprop('newProperty'),然后可以进行类似obj.newProperty = 3val = obj.newProperty的调用,addprop()的返回值p可以用于设置属性的属性(如‘hidden’),或通过delete(p)来删除属性。具体可以参考matlab的文档:

  • Dynamic Properties — Adding Properties to an Instance

  • dynamicprops class

hgsetget 类也是 handle 的子类,它是用于通过 set 和 get 方法派生句柄类的抽象类,在matlab图像里我们经常使用的set和get函数就是通过它来实现的,比如 set(h,'property',value)。然而matlab称在以后的版本可能会删除hgsetget。推荐改用 matlab.mixin.SetGet。另外我们还可以对内置的类型(如double)进行子类化。

7. 封闭(sealed)类、方法和属性

封闭类不能被子类化,封闭的方法或属性不能在子类里重新定义,这类似于C++的final关键字,下面是定义封闭的例子(封闭类、封闭方法和封闭属性)

classdef(Sealed = true) myclass
methods(Sealed = true)
properties(Sealed = true)

8. 抽象(abstract)方法和属性

抽象方法简单来说是具有函数头的方法,但不是函数体(还没有实现),它们可以定义当前和未来子类的通用接口(类似与C++的虚函数),抽象方法必须由子类来实现,因此子类集成超类是一种必然的条件。当然如果所有子类中的实现都是一样的,最好在超类写一个通用的方法以被子类继承。也就是说,当我们知道子类需要具有特定的方法,这些方法的实现会有所不同的时候,我们就可以使用抽象了。

比如我们有一个shape超类,它具有许多子类,如球体、立方体、椭圆体、金字塔等。我们想要每个子类(以及未来可能的子类)有一个 calculateVolume() 方法来计算这些形状的体积。每一种子类的函数的计算的方法都有所不同,但是通过shape超类的的方法的抽象,我们可以在每个子类里来具体实现这些方法。

属性也可以是抽象的,但是用处不大,它们必须在子类里定义。

一个具有一个或多个抽象的方法或属性的类被认为是抽象类,我们无法从中创建实例,任何没有实现抽象方法和属性的子类也是抽象的,实质上是将部分或全部抽象方法和属性的实现委托给了更多的子类。

我们可以使用Abstract将方法块定义为抽象,在编写函数的时候,我们可以不包含主体:

methods(Abstract = true)
    function vol = calculateVolume(obj,units);
    function area = calculateSurfaceArea(obj,units);
    function obj = doubleSize(obj);
end

9. Operator 重载

每次使用 Matlab 运算符,例如

+ - .* * ./ .\ / \ .^ ^ < > <= >=
== ~ ~= & | && || : ' .' [] [;] () .

实际上是调用了命名函数的简写或语法,如plus()minus()等,我们可以通过使用同名的类方法为这些操作符定义自定义行为。由于类方法是动态分派的,因此当我们对对象使用相应的运算符时,我们自己版本的这些函数就会执行。比如我们可以在date类里编写自己的plus方法,将日期相加,然后使用d1+d2调用这个函数,类调用会自动转换为plus(d1, d2),然后调用我们对这些函数的实现。具体实现是我们添加plus方法:

classdef date
   % write a description of the class here.
       properties (Hidden = false)
       % define the properties of the class here, (like fields of a struct)
           minute = 0;
           hour;
           day;
           month;
           year;
       end
       properties(Constant = true)
           DAYS_PER_YEAR =  365;
           MONTHS_PER_YEAR = 12;
           WEEKS_PER_YEAR  = 52;
       end


       methods
       % methods, including the constructor are defined in this block
           function obj = date(minute,hour,day,month,year)
           % class constructor
               if(nargin > 0)
                 obj.minute = minute;
                 obj.hour   = hour;
                 obj.day    = day;
                 obj.month  = month;
                 obj.year   = year;
               end
           end
           function obj = plus(obj1, obj2)
               obj = obj1;
               obj.day = obj1.day + obj2.day;
           end
           
       end
       methods
           function obj = rollDayCall(obj, numdays)
                obj = rollDay(obj,numdays)
           end
       end
       methods(Access = private)
           obj = rollDay(obj,numdays)
       end

       methods(Static = true)
           function printCurrentDate()
             display(datestr(now));
           end
       end

end

我们进行一下测试,可以看到:

d1 = date(0,3,27,2,1998);
d2 = date(0,3,2,2,1998);
d = d1+d2

d最后的day是d1和d2的day的和。
在这里插入图片描述

更具体的参考我们可以看:运算符重载

运算符保留其自然优先级,如* 在运算顺序上优先于 +,即使一个或两个运算符被重载。

另一个有用的重载方法是 display() - 它是当我们不用分号禁止显示输出时自动显示对象的函数。编写我们自己的显示函数允许我们以任何我们喜欢的方式显示对象。

有时,重复使用属于内置函数(如 plot())的简明信息名称非常有用。虽然 plot 不会被自动调用,也不与操作符相对应,但它在 Matlab 中的使用频率很高,因此在我们自己的对象中重复使用这个名称可以很好地自我记录其行为(假设我们的 plot 函数做了一些合理的事情)。

如果重载了运算符或函数,但出于某种原因想要使用原始实现,请使用 builtin() 函数,该函数将函数的字符串名称作为第一个输入,然后是该函数的输入。

具体的可以参考matlab的文档:builtin

有两个非常重要的函数经常被重载,值得特别一提:subsrefsubsasgn。在索引操作中使用点操作符.、括号()或大括号 {} 时,会调用 subsref;在赋值操作中使用它们时,会调用 subsasgn。通过重载这些函数,我们可以为我们的类创建自定义行为。

例如,假设我们编写了自己的数据结构类,并希望调用 obj(3) 来获取结构中的第三个元素,我们就可以通过重载 subsref 来实现这一目标。下面是这两个函数的定义:

function obj = subsasgn(obj, S, value)
function value = subsref(obj, S)

obj 是调用对象,如 obj.prop 或 obj(3)

value 是新的或返回的值,如 obj.prop = value 或 value = obj.prop

S 是具有两个字段的结构:type 和 subs: type是"()""{}"".",具体取决于调用。subs 是cell数组或实际使用的下标字符串。

在涉及多个运算符(如 obj(5,9).prop(1:19)=value)的复杂调用中,对 subsasgn 进行一次调用,并将调用中的所有信息传递给该函数。在本例中,S 是 具有以下值的结构数组。

S(1)S(2)S(3)
S(1).type=‘()’S(2).type=‘.’S(3).type=‘()’
S(1).subs={5,9}S(2).subs=‘prop’S(3).subs={1:10}

这里也把有关的参考给列出来:

  • subsref
  • subsasgn
  • Code Patterns for subsref and subsasgn Methods
  • 对象数组索引

10. 类数组

同类对象可以一起存储在对象数组(元胞数组和结构体也是可以的),其操作方式与数字数组类似。我们可以将对象连接在一起,并以通常的方式在这些数组中建立索引。

d1 = date(0,3,27,2,1998);   % 创建第一个日期对象
d2 = date(1,4,22,3,2008);   % 创建第二个日期对象
dates = [d1 d2];            % 可以把这两个对象连接成一个数组
[nrows ncols] = size(dates) % 也可以使用数组的函数
d1 = dates(1,1);            % 检索数组第一个条目
dates(1,1) = d1;            % 赋值数组第一个条目

在这里插入图片描述
单个日期对象的类型实际上是由日期对象组成的对象数组,尽管大小为 1x1。在 Matlab 中,几乎所有东西都可以组成数组,对象也不例外。其后果之一是,涉及对象数组的方法调用会调度与只涉及一个对象相同的方法;这包括调用 subsref()subsasgn()

11. 事件events

Matlab 现在对基于事件的编程有很好的支持,在这种编程中,对象会根据状态的变化触发事件,并通知一个或多个已注册为监听器的其他对象。当适当的控制流取决于程序外部的事物(如用户与图形界面或环境传感器的交互)时,这种编程方式就特别有用。不过,它本身也是一种有用的范例,尤其是对于模拟而言。

首先,所有涉及的类都必须继承自handle类(或其子类之一)。触发类必须在其类定义中声明一个事件块。事件块的属性与方法和属性块一样,都定义了事件访问控制access control。

ListenAccess 属性决定了可以在哪里创建事件监听器,而 NotifyAccess 则决定了可以在哪里触发事件。在下面的示例中,我们将 ListenAccess 设置为 public,这样就可以在任何地方将对象注册为监听器,而将 NotifyAccess 设置为 protected,这样就只有 date 类(或 date 的任何子类)的方法可以触发事件。

这一部分不是本文的重点,具体可以参考matlab的文档:

  • 事件和侦听程序语法
  • 侦听对属性值的更改
  • 事件和侦听程序概念
  • 事件和侦听程序概述
  • 事件

12. mataclass 元类

Matlab的 有一个相当新颖的功能mataclass ,它允许动态地检查特定类的属性。每个使用 classdef 语法的类具有相应的元类,可以调用?得到元类。生成的对象存储了类的方法、属性、事件、超类等信息及其属性。元类可用于编写高度通用的代码。查看类树(viewClassTree())方法(可显示项目的完整类层次结构)广泛使用了元类,代码如下所示:

function  viewClassTree(directory)
% View a class inheritence hierarchy. All classes residing in the directory
% or any subdirectory are discovered. Parents of these classes are also
% discovered as long as they are in the matlab search path. 
% There are a few restrictions:
% (1) classes must be written using the new 2008a classdef syntax
% (2) classes must reside in their own @ directories.
% (3) requires the bioinformatics biograph class to display the tree.
% (4) works only on systems that support 'dir', i.e. windows. 
%  
% directory  is an optional parameter specifying the directory one level
%            above all of the @ class directories. The current working
%            directory is used if this is not specified.
%Written by Matthew Dunham 
if nargin == 0
    directory = '.';
end
info = dirinfo(directory);
baseClasses = vertcat(info.classes);
if(isempty(baseClasses))
    fprintf('\nNo classes found in this directory.\n');
    return;
end
allClasses = baseClasses;
for c=1:numel(baseClasses)
   allClasses = union(allClasses,ancestors(baseClasses{c}));
end
matrix = zeros(numel(allClasses));
map = struct;
for i=1:numel(allClasses)
   map.(allClasses{i}) = i; 
end
for i=1:numel(allClasses)
    try
        meta = eval(['?',allClasses{i}]);
        parents = meta.SuperClasses;
    catch ME
        warning('CLASSTREE:discoveryWarning',['Could not discover information about class ',allClasses{i}]);
        continue;
    end
    for j=1:numel(parents)
       matrix(map.(allClasses{i}),map.(parents{j}.Name)) = 1;
    end
end
for i=1:numel(allClasses)
    allClasses{i} = ['@',allClasses{i}]; 
end
view(biograph(matrix,allClasses));
function info = dirinfo(directory)
%Recursively generate an array of structures holding information about each
%directory/subdirectory beginning, (and including) the initially specified
%parent directory. 
        info = what(directory);
        flist = dir(directory);
        dlist =  {flist([flist.isdir]).name};
        for i=1:numel(dlist)
            dirname = dlist{i};
            if(~strcmp(dirname,'.') && ~strcmp(dirname,'..'))
               info = [info, dirinfo([directory,'\',dirname])]; 
            end
        end
end
function list = ancestors(class)
%Recursively generate a list of all of the superclasses, (and superclasses
%of superclasses, etc) of the specified class. 
    list = {};
    try
        meta = eval(['?',class]);
        parents = meta.SuperClasses;
    catch
        return;
    end
    for p=1:numel(parents)
        if(p > numel(parents)),continue,end %bug fix for version 7.5.0 (2007b)
        list = [parents{p}.Name,ancestors(parents{p}.Name)];
    end
end
end

在这里插入图片描述
我们在当前路径下查看一下类的层次:

viewClassTree()

在这里插入图片描述

以下示例函数查找特定类的所有超类,包括其超类的超类。metaclass() 函数的运行方式就像 ?运算符,但可以与字符串名称一起使用,而 ?需要对象的实例。

function list = ancestors(class)
% input is the string name of the base class
% output is a cell array of ancestor class names
    list = {};
    meta = metaclass(class);
    parents = meta.SuperClasses;
    for p=1:numel(parents)
        list = [parents{p}.Name,ancestors(parents{p}.Name)];
    end
end

在这里插入图片描述
以下是可用数据类型。

metadata = ?date

在这里插入图片描述

整理自:

  1. Object Oriented Programming in Matlab: basics
  2. Object Oriented Programming in Matlab: More advanced topics

看了这篇博客应该对基本的一些matlab面向对象编程的知识有了一定的了解,如果想继续往下深入推荐matlab面向对象编程的官方文档一起学习:

MATLAB® 2023b Object-Oriented Programming

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/253356.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

STM32_通过Ymodem协议进行蓝牙OTA升级固件教程

目录标题 前言1、OTA升级的重要性和应用场景2、理论基础2.1、单片机的启动流程2.2、什么是IAP&#xff1f;2.3、什么是OTA&#xff1f;2.4、什么是BootLoader&#xff1f;2.5、Ymodem协议是什么&#xff1f;2.6、IAP是如何实现的&#xff1f; 3、具体操作3.1、软硬件工具准备3.…

类加载机制

1.类加载的生命周期 其中类加载的过程包括了加载、验证、准备、解析、初始化五个阶段。在这五个阶段中&#xff0c;加载、验证、准备和初始化这四个阶段发生的顺序是确定的&#xff0c;而解析阶段则不一定&#xff0c;它在某些情况下可以在初始化阶段之后开始&#xff0c;这是为…

计算机中msvcr120.dll丢失怎样修复,这5个方法可以搞定

几乎在所有操作系统中&#xff0c;可分为两种库&#xff0c;一种是静态库&#xff08;.lib&#xff09;&#xff0c;另一种是动态库&#xff08;.dll&#xff09;。 为什么很多小伙伴在打开软件的时候会弹出“由于找不到XXX.dll文件&#xff0c;无法继续执行代码、、、、、、”…

大数据技术之 Kettle(PDI)

Kettle 第一章 Kettle概述1.1、ETL简介1.2、Kettle简介1.3、作业 和 转换 概念1.4、核心组件1.5、下载安装 第二章 控件使用2.1、初体验&#xff1a;csv 转换 excel 示例2.2、转换2.2.1、输入控件2.2.1.1、表输入 2.2.2、输出控件2.2.2.1、表输出2.2.2.2、更新&插入/更新2.…

分享66个Java源码总有一个是你想要的

分享66个Java源码总有一个是你想要的 学习知识费力气&#xff0c;收集整理更不易。 知识付费甚欢喜&#xff0c;为咱码农谋福利。 链接&#xff1a;https://pan.baidu.com/s/1hKlZJB3KrHcOuKWyV1xjKw?pwd6666 提取码&#xff1a;6666 项目名称 ava web个人网站项目 ea…

【C++11特性篇】C++11中の【override】【final】关键字——帮助用户检测是否重写

前言 大家好吖&#xff0c;欢迎来到 YY 滴C系列 &#xff0c;热烈欢迎&#xff01; 本章主要内容面向接触过C的老铁 主要内容含&#xff1a; 欢迎订阅 YY滴C专栏&#xff01;更多干货持续更新&#xff01;以下是传送门&#xff01; 目录 一.【override】【final】关键字——帮…

软件测试之鲁棒性测试

文章目录 前言一、鲁棒性测试是什么&#xff1f;二、鲁棒性测试的目的三、测试原理3.1 错误数据处理3.2 异常情况处理 前言 Bootloader软件刷写鲁棒性(Robustness)测试是指对Bootloader软件进行连续多次的刷写测试&#xff0c;且一次Fail都没发生&#xff0c;以此验证Bootload…

基于java+swing+mysq学生成绩管理系统(含课程报告)

基于javaswingmysq学生成绩管理系统_含课程报告 一、系统介绍二、功能展示三、项目相关3.1 乱码问题3.2 如何将GBK编码系统修改为UTF-8编码的系统&#xff1f; 四、其它1.其他系统实现 五、源码下载 一、系统介绍 本系统使用 Swing MySQL IntelliJ IDEA 开发。为管理人员提供…

【精选】计算机网络教程(第3章数据链路层)

目录 前言 第3章数据链路层 1、差错检测&#xff08;CRC&#xff09; 2、点对点协议&#xff08;了解应用场景&#xff09; 3、什么是碰撞域&#xff0c;什么是广播域 碰撞域&#xff08;Collision Domain&#xff09;&#xff1a; 广播域&#xff08;Broadcast Domain&a…

Linux驱动开发学习笔记4《设备树下的LED驱动实验》

目录 一、设备树LED驱动原理 二、硬件原理图分析 三、实验程序编写 1.修改设备树文件 2.LED 灯驱动程序编写 3.编写测试APP 四、运行测试 1. 编译驱动程序和测试APP &#xff08;1&#xff09; 编译驱动程序 &#xff08;2&#xff09; 编译测试APP ​ 2.运行测试 一、…

【Hive_03】单行函数、聚合函数、窗口函数、自定义函数、炸裂函数

1、函数简介2、单行函数2.1 算术运算函数2.2 数值函数2.3 字符串函数&#xff08;1&#xff09;substring 截取字符串&#xff08;2&#xff09;replace 替换&#xff08;3&#xff09;regexp_replace 正则替换&#xff08;4&#xff09;regexp 正则匹配&#xff08;5&#xff…

open3d.core导入失败问题

官网的例子中需要导入o3c但是我的代码提示导入失败&#xff0c;百度一下没有找到问题所在 多次测试后发现。 可以不用import open3d.core as o3c 使用的时候直接 o3d.core.tensor就可以了 import open3d as o3d #import open3d. as o3c import numpy as np import matplotl…

Java之Clonable接口和深浅拷贝

Clonable接口 我们船舰了一个人的对象&#xff0c;想要克隆一个一模一样的对象&#xff0c;可以用到object类里面的克隆方法 object不是所有类的父类吗&#xff1f;那为什么用person1点不出这个方法呢&#xff1f;可以看一下源码 这是Object类里面的clone方法的声明&#xff0…

flask简单应用-1

目标&#xff1a; 做一个搜索网页&#xff0c;搜索当前路径下是否含有指定关键字的文件&#xff0c;如果有就列出来&#xff0c;没有返回消息 第一步&#xff1a;我们需要先显示一个搜索页面&#xff0c;页面上需要有一个可以输入的对话框&#xff0c;一个按钮执行搜索 建立ht…

软件测试找了两个月了,简历投了10万多次,找不到工作怎么办?

是行情不好吗&#xff1f;我觉得不是&#xff0c;为什么别人可以找到&#xff0c;而你找了两个月还找不到。 只能说明一个原因&#xff0c;你学的东西和企业需要有些差距。 现在&#xff0c;软件测试已经不是过去那样只会点点点就可以找到一个合适的工作。 首先因为大环境原…

使用 Timm 库替换 RT-DETR 主干网络 | 1000+ 主干融合RT-DETR

文章目录 前言版本差异说明替换方法parse_moedl( ) 方法_predict_once( ) 方法修改 yaml ,加载主干论文引用timm 是一个包含最先进计算机视觉模型、层、工具、优化器、调度器、数据加载器、数据增强和训练/评估脚本的库。 该库内置了 700 多个预训练模型,并且设计灵活易用。…

Java入门学习笔记一

一、Java语言环境搭建 1、JAVA语言的跨平台原理 1.1、什么是跨平台性&#xff1f; 跨平台就是说&#xff0c;同一个软件可以在不同的操作系统&#xff08;例如&#xff1a;Windows、Linux、mad&#xff09;上执行&#xff0c;而不需要对软件做任务处理。即通过Java语言编写的…

【C语言】操作符详解(三)

目录 逗号表达式 下标访问[ ]&#xff0c;函数调用&#xff08; &#xff09; 下标引用操作符[ ] 函数调用操作符&#xff08;&#xff09; 逗号表达式 exp1&#xff0c;exp2&#xff0c;exp3&#xff0c;...expN 逗号表达式&#xff0c;就是用逗号隔开的多个表达式…

C语言第四十六弹---最快方法找到杨氏矩阵中的数下标

C语言实现最快方法找到杨氏矩阵中数下标。 定义&#xff1a;杨氏矩阵是一种用于描述Young 表和表示论的工具&#xff0c;它在代数几何和组合数学中有广泛的应用。一个杨氏矩阵是一个以若干个正整数构成的矩形表格&#xff0c;且每行和每列的元素单调递增。 从定义中可获得条件…

管理类联考——英语二——考点+记忆篇——小作文——按行应战

题目要求100字 Dear Mr/Ms.XX, 空两格 I am writing this letter in order to express my sincere gratitude感谢/congratulation祝贺/introduction介绍/invitation邀请/application申请/opinion观点/comfort安慰/complaint抱怨/apology道歉 about sth to you for sth(doing s…