面向对象编程根据要处理的工程抽象出对象,并用代码描述对象的属性、方法和事件。MATLAB提供了比较完备的面向对象编程环境。而且,目前的版本将MATLAB的源码根据面向对象编程的思想进行了重构,提供了计算和绘图的另外一种方法和途径。[大谦MATLAB,dqmatlab点com]
面向对象编程的特点
在使用设计良好的类时,面向对象编程可以显著提高代码的重用性,并使程序更易于维护和扩展。用类和对象编程与一般的结构化编程有下面一些主要区别:
(1)能实现函数和运算符重载。
(2)可以覆盖已经存在的MATLAB函数表示的方法。
(3)当把用户定义的对象作为参数调用函数时,MATLAB首先要进行检查,看是否有定义对象类的方法。如果有,则调用它。
(4)可以实现数据的封装。
(5)对象属性在命令行中不可见,只能用类方法访问它们。
(6)可以创建类的继承层次。子类可以从一个父类(单继承)和多个父类(多继承)那里进行继承。利用继承,可以共享父函数。
(7)可以用组合创建类,其中一个对象包含另一个对象。此种方法适用于一种对象是另一种对象的一部分的情况。
由于篇幅所限,本节主要介绍在MATLAB中创建类和对象的基本方法和流程。
类的定义
类是一种模板,用于提供对类的所有实例共有元素的描述。类的成员包括定义类的属性、方法和事件。
MATLAB中的类用代码块进行定义。
1.生成类的块
MATLAB在组织类的时候,将代码组织成块,如下所示,每个块以关键词开始,以end语句结束:
classdef…end ——定义所有类组件。
properties…end——声明属性名,定义属性并指定默认值。
methods…end——声明方法签名,定义方法和函数代码。
events…end ——声明事件名称,进行定义。
enumeration…end ——声明枚举类的成员和值。
Properties,methods,events和enumeration都是关键字,它们只应用在calssdef块中。
2.类定义块
类文件中的classdef块包含类的定义代码,以classdef关键字开始,以end语句结束。
classdef(ClassAttributes) ClassName < SuperClass
...
end
ClassAttributes定义类的特性,SuperClass定义类的父类,即继承性。
3.属性块
属性块包含属性的定义代码,以properties关键字开始,以end语句结束。
classdef ClassName
properties(PropertyAttributes)
...
end
...
end
例如,下面的类定义一个名为Prop1的属性。
classdef MyClass
properties
Prop1
end
...
end
使用点标记可以获取属性的值。
A = MyClass;
设置Prop1属性的值。
A.Prop1=10.0;
4.方法块
方法块包含定义类方法的函数,以methods关键字开始,以end语句结束。
classdef ClassName
properties
PropertyName
end
methods
function obj=ClassName(arg1,...)
obj.PropertyName=arg1;
...
end
function ordinaryMethod(obj,arg1,...)
...
end
end
在上面的代码中,ClassName方法被称为构造函数方法,用于创建类的实例。
给MyClass类添加一个构造函数,并设置属性值。
classdef MyClass
properties
Prop1
end
methods
function obj=MyClass(Prop1)
obj.Prop1=prop1;
end
end
end
创建MyClass类的实例A:
A=MyClass(date);
对于下面代码定义的一般方法:
classdef MyClass
methods
function out = ordinaryMethod(obj,arg1)
...
end
end
end
可以用MATLAB函数语法或点标记两种方式调用一般方法:
obj = MyClass;
r = ordinaryMethod(obj,arg1);
或
obj = MyClass;
r = obj.ordinaryMethod(arg1);
5.事件块
事件块定义类的事件,以events关键字开始,以end语句结束。要定义事件,可以在events块中声明一个事件名称。使用handle类的notify方法触发事件。只有继承自handle类的类才可以定义事件。
6.枚举类
在MATLAB中用enumeration块定义枚举,其中以enumeration关键字开始,以end语句结束。
classdef ClassName < SuperClass
enumeration
EnumerationMember
end
...
end
例如,下面的类定义两个枚举成员,表示逻辑上的false和true。
classdef Boolean < logical
enumeration
No(0)
Yes(1)
end
end
7.函数重载和运算符重载
类可以通过重新定义MATLAB函数来实现名字相同的方法,这就是重载。在定义与已有MATLAB类型类似的特别类时,重载很有用。例如,可以对类对象实现关系操作、绘图操作和其他常用的MATLAB函数定义的操作。
重载一个MATLAB函数:
定义一个名字相同的要重载的函数。
确保方法的变量列表接受类对象,MATLAB用于确定调用哪个版本。
运算符重载是重新定义MATLAB中运算符对应的函数,实现运算符重载以后,可以对对象进行类似数值运算和逻辑运算那样的操作。
在MATLAB中实现类对象的运算符,需要实现相关的类方法。每个运算符都有一个相关的函数,如“+”运算符相关的函数为plus.m,“*”运算符相关的函数为mtimes.m。可以通过创建合适名称的类方法来实现任何的运算符。
节中的实例在直线段cline类中实现了“+”和“*”运算符重载,从而可以很方便地实现直线段的平移和缩放。
类的特性
类的特性如表3-7所示。通过定义特性可以修改类的行为。特性的值在classdef块中进行定义。
classdef(Attribute1 = value1, Attribute2 = value2,...) ClassName
...
end
表3-7 类的特性
| 特性名称 | 类 | 描 述 |
|---|---|---|
| Abstract | Logical(默认值为=false) | 如果指定为true,则该类为抽象类,无法实例化 |
| AllowedSubclasses | meta.class对象或meta.class对象构成的单元数组 | 列出可以作为本类父类的类。指定子类为下面形式的meta.class对象: 单一的meta.class对象 meta.class对象构成的单元数组。一个空的单元数组{},与Sealed类等同 |
| ConstructOnLoad | Logical(默认值为=false) | 如果为true,则MATLAB从MAT文件载入对象时调用类的构造函数。这样,实现构造函数,从而它可以在没有参数的情况下被调用时不会生成出错信息 |
| HandleCompatible | 对于值类,logical(默认值为=false) | 当指定为true时,该类可以用作句柄类的父类 |
| Hidden | Logical(默认值为=false) | 如果为true,则该类不会出现在superclasses或help函数的输出中 |
| InferiorClasses | meta.class对象或meta.class对象构成的单元数组 | 使用本特性建立类的优先关系 |
| Sealed | Logical(默认值为=false) | 如果为true,则该类不能被子类化 |
类成员的特性在classdef,properties,methods和events定义块中指定。语法格式如下:
classdef(attribute-name = expression, ...) ClassName
properties(attribute-name = expression, ...)
...
end
methods(attribute-name = expression, ...)
...
end
events(attribute-name = expression, ...)
...
end
end
类文件和目录
在MATLAB中,类的代码以M文件的形式被保存,类文件的名称就是类的名称,扩展名为.m。包含类文件的目录可以有两种方式:
路径目录——是MATLAB路径上的目录;
类目录——是路径目录下面目录,名称为“@”符号加类名,例如@MyClass。
定义类文件有两种方式:
创建一个自包含的类定义文件,放在路径目录或类目录中。目录的组织如图3-6所示。将各个自包含的类文件都放在路径目录里面,文件名必须与类的名称相匹配,并且扩展名为.m。
用多个文件定义一个类,需要使用类目录(MATLAB的早期版本采用这种方式)如图3-7所示,将一个类的所有类定义文件放到一个以“@”打头的目录中,“@”后面跟类的名称。该目录必须位于路径目录中,并且一个类目录只能定义一个类。
图3-6 定义类文件的方式一 图3-7 定义类文件的方式二
类的优先级
当有多个名字相同的类定义文件时,文件在MATLAB路径上的位置决定文件的优先级。所有类定义文件按照在路径上的先后顺序确定优先级,不管文件是否包含在类目录中。示例文件如表3-8所示。
表3-8 示例文件
| 在路径上的次序 | 目 录 和 文 件 | 文 件 定 义 |
|---|---|---|
| 1 | fldr1/Foo.m | Foo类 |
| 2 | fldr2/Foo.m | Foo函数 |
| 3 | fldr3/@Foo/Foo.m | Foo类 |
续表
| 在路径上的次序 | 目 录 和 文 件 | 文 件 定 义 |
|---|---|---|
| 4 | fldr4/@Foo/bar.m | bar方法 |
| 5 | fldr5/Foo.m | Foo类 |
下面分析表3-8中各个版本的Foo的优先级。
类fldr1/Foo.m的优先级比fldr3/@Foo的高,因为fldr1/Foo.m在路径上的位置比fldr3/@Foo的靠前。
类fldr3/@Foo的优先级比fldr2/Foo.m的高,因为fldr3/@Foo是类目录中的类,而fldr2/Foo.m不是类。类目录中的类的优先级比函数的高。
函数fldr2/Foo.m的优先级比fldr5/Foo.m的高,因为fldr2/Foo.m在路径上的位置比fldr5/Foo.m的靠前,fldr5/Foo.m不在类目录中。没在类目录中定义的类,遵循函数的先后顺序确定优先级。
类fldr3/@Foo的优先级比类fldr4/@Foo的高,因为方法bar不会被认为是fldr3/@Foo中Foo类的一部分。
如果fldr3/@Foo/Foo.m不包含classdef关键字,则fldr4/@Foo/bar.m成为fldr3/@Foo中Foo类的一个方法。
面向对象编程实例
【例3-25】通过定义一个名为cline的新类,可实现直线段的定义和绘制,以及平移与缩放等几何变换。
1.cline类的数据结构
cline类用直线段的起点和终点坐标值定义直线段。其对象ln是一个具有4个字段的结构。这4个字段分别为ln.startx,ln.starty,ln.endx和ln.endy。
properties
startx
starty
endx
endy
end
2.cline类的方法
cline类实现下面的方法:
构造函数cline
draw方法
重载的+和*运算符
(1)cline类的构造函数
下面是cline类的构造函数cline。
methods
function ln=cline(varargin)
%cline对象的构造函数
%ln=cline(startx,starty,endx,endy)
switch nargin
case 0
%如果没有输入参数,则创建一个默认对象
ln.startx=0;
ln.starty=0;
ln.endx=0;
ln.endy=0;
case 1
%如果只有一个参数,则返回它
if(isa(varargin{1},'cline'))
ln=varargin{1};
else
error('输入参数不是cline对象。')
end
case 4
%用指定的坐标值创建对象
ln.startx=varargin{1};
ln.starty=varargin{2};
ln.endx=varargin{3};
ln.endy=varargin{4};
otherwise
error('输入参数个数错误。')
end
end
end
cline类有3个构造函数,它们具有不同的形式。
没有输入参数——如果调用没有参数的构造函数,则MATLAB返回一个带空字段的cline对象。
输入参数为对象——如果调用输入参数为对象的构造函数,则MATLAB返回该对象。
输入参数为直线段起点和终点的坐标值——class函数创建cline对象,并在后面由构造函数返回。下面是一个使用cline类构造函数的例子:
ln=cline(0,0,10,20)
这里将创建一个起点坐标为(0,0),终点坐标为(10,20)的直线段。
(2)cline类的draw方法
function draw(ln)
x1=[ln.startx ln.endx];
y1=[ln.starty ln.endy];
line(x1,y1)
end
(3)重载算术运算符
在对直线段进行平移和缩放操作时,实际上是对直线段的起点和终点的坐标值进行加法、减法或乘法计算,然后利用得到的结果进行绘图。在本例中,为cline类定义了plus和mtimes方法,以便实现加和乘法等运算。
重载“+”运算符
对图形元素进行平移变换,实际上是对该图形元素的控制点进行平移变换,然后重新绘图。点的平移变换,实际上就是将该点的横坐标值和纵坐标值分别加上或减去x方向和y方向的平移值。如果定义向右和向上平移为正,向左和向下平移为负,则可以将相加和相减运算统一为相加运算。直线段的控制点为其起点和终点,对直线段进行平移,只须计算其起点和终点的平移即可。
如果lno为cline类对象,v为一数组(其值分别表示在x和y方向上平移值的大小),表达式lno+v调用plus函数,则下面的函数为cline类定义“+”运算符。
function ln = plus(lno,v)
if(isa(lno,'cline'))
x1=lno.startx+v(1);
y1=lno.starty+v(2);
x2=lno.endx+v(1);
y2=lno.endy+v(2);
ln=cline(x1,y1,x2,y2);
else
error('参数类型错误。')
end
end
该函数首先判断第一个输入参数是不是cline类型的对象,如果是,则将该对象所表示的直线段的起点和终点的坐标值分别加上x方向和y 方向的平移值;如果不是,给出出错信息。
重载“*”运算符
放大或缩小直线段,实际上是将直线段的起点和终点坐标值乘以缩放系数,然后利用得到的坐标值进行绘图。
如果lno为cline类对象,v为一数组(其值分别表示x和y方向上的缩放比例),表达式lno*v调用mtimes.m函数,则下面的函数为cline类定义“*”运算符。
function ln = mtimes(lno,v)
if(isa(lno,'cline'))
x1=lno.startx*v(1);
y1=lno.starty*v(2);
x2=lno.endx*v(1);
y2=lno.endy*v(2);
ln=cline(x1,y1,x2,y2);
else
error('参数类型错误。')
end
end
使用重载的运算符
下面用methods命令列出类的所有方法。
methods cline
类 cline 的方法:
cline draw mtimes plus
给定cline对象ln=cline(1,0,8,5),MATLAB在使用语句ln2=ln+[3 -1]时调用plus函数,在使用语句ln3=ln*[2 2]时调用mtimes函数。然后分别绘制这3条直线的图形。
ln=cline(1,0,8,5);
ln2=ln+[3 -1];
ln3=ln*[2 2];
draw(ln);
hold on
draw(ln2);
draw(ln3);
hold off
生成图 3-8所示的图形。图中最上面是最初生成的直线段,最下面是该直线段向下平移1个单位、向右平移3个单位后的图形,中间是放大两倍后的图形。