定义类方法和函数
方法代码块
在 classdef
代码块内的 methods
代码块中将方法定义为 MATLAB® 函数。构造函数方法与类同名,并返回类的初始化对象。要创建具有该实例独有属性值的对象,请在类构造函数中为属性赋值。用 end
语句终止所有方法函数。
classdef ClassName
properties
PropertyName
end
methods
function obj = ClassName(arg1,...)
obj.PropertyName = arg1;
...
end
function ordinaryMethod(obj,arg1,...)
...
end
end
methods (Static)
function staticMethod(arg1,...)
...
end
end
end
方法调用语法
与 C++ 和 Java® 等语言不同的是,MATLAB 中没有传递给所有方法的特殊隐藏类对象。必须将类的对象显式传递给方法。最左边的参数不需要是类对象,参数列表可以有多个对象。MATLAB 调度由主导参数的类定义的方法。有关详细信息,请参阅方法调用。
方法在被调用时必须位于 MATLAB 路径上。例如,如果创建一个对象,然后将当前文件夹更改为对方法文件不可见的文件夹,则调用该方法时会出错。
请在您的 MATLAB 代码中始终使用区分大小写的方法名称。
普通方法
使用 MATLAB 函数语法或圆点表示法调用普通方法。例如,假设您有一个定义 ordinaryMethod
的类。传递定义类的对象和任何需要的参数。
classdef MyClass
methods
function out = ordinaryMethod(obj,arg1)
...
end
end
end
使用类的对象 obj
和以下任一语法调用 ordinaryMethod
:
obj = MyClass;
r = ordinaryMethod(obj,arg1);
r = obj.ordinaryMethod(arg1);
静态方法
静态方法不需要类的对象。要调用静态方法,请在方法名称前加上类名,以便 MATLAB 确定哪个类定义该方法。
classdef MyClass
methods (Static)
function out = staticMethod(arg1)
...
end
end
end
使用语法 classname.methodname
调用 staticMethod
:
r = MyClass.staticMethod(arg1);
有关不需要其类对象的方法的信息,请参阅静态方法。
私有方法
使用 Access
方法属性创建一个私有方法。您不需要使用私有文件夹。
有关方法属性的列表,请参阅方法特性。
有关方法的更多详细信息
类相关函数
您可以在包含类定义 (classdef
) 的文件中定义不是类方法的函数。在 classdef - end
代码块之外但在与类定义相同的文件中定义局部函数。classdef
文件中定义的函数与局部函数类似。您可以从同一文件的任何位置调用这些函数,但是,它们在您用于定义它们的文件之外不可见。
classdef
文件中的局部函数对于仅在该文件中使用的工具函数非常有用。这些函数可以接受或返回类实例参数,但不会像普通方法中那样是必需的。例如,以下代码在 classdef
代码块之外定义 myUtilityFcn
:
classdef MyClass
properties
PropName
end
methods
function obj = MyClass(arg1)
obj.PropName = arg1;
end
end
end % End of classdef
function myUtilityFcn
...
end
您还可以创建包函数,这要求在调用这些函数时使用包名称。
如何重载函数和运算符
为您的类重载 MATLAB 函数,方法是定义一个与要重载的函数同名的类方法。在类实例中调用该函数时,MATLAB 会调度该类方法。
您可以通过用适当的名称定义类方法来重载 MATLAB 算术、逻辑、关系和索引运算符。
有关为该类定义的运算的列表,请参阅 handle
类。从 handle
派生的所有类都继承这些方法。
在单独的文件中定义方法的规则
以下规则适用于在单独的文件中定义的方法:
- 要为在单独文件中定义的方法指定属性,请在
classdef
文件的方法代码块中声明此方法。使用方法代码块指定属性值。 - 将方法代码块中声明的语法(如果使用)与方法的
function
行匹配。 - 该单独文件必须位于类 (
@
) 文件夹中。 - 类构造函数方法必须在
classdef
文件中定义。构造函数不能位于单独的文件中。 - 必须在
classdef
文件中定义句柄类delete
方法。delete
方法不能位于单独的文件中。所有在其名称中使用圆点的函数都必须在
classdef
文件中定义,包括:- 转换器方法,这些方法必须使用包名称作为类名的一部分,因为类包含在包中
- 属性 set 和 get 访问方法
有关在单独的文件中定义方法的详细信息,请参阅在单独文件中定义方法
创建简单类
设计类
类的基本目的是定义封装数据的对象以及对该数据执行的操作。例如,BasicClass
定义一个属性和对该属性中的数据执行操作的两个方法:
Value
- 此属性包含存储在类对象中的数值数据roundOff
- 此方法将属性值舍入到两位小数multiplyBy
- 此方法将属性值乘以指定数值
以下是 BasicClass
的定义:
classdef BasicClass
properties
Value {mustBeNumeric}
end
methods
function r = roundOff(obj)
r = round([obj.Value],2);
end
function r = multiplyBy(obj,n)
r = [obj.Value] * n;
end
end
end
有关类语法的汇总,请参阅 classdef
。
要使用类,请执行以下操作:
- 将类定义保存在与该类同名的
.m
文件中。 - 创建该类的一个对象。
- 访问属性以将数据赋给属性。
- 调用方法以对这些数据执行操作。
创建对象
使用类名创建类的一个对象:
a = BasicClass
a =
BasicClass with properties:
Value: []
属性值最初为空。
访问属性
使用对象变量加点加属性名称的方式为 Value
属性赋值:
a.Value = pi/3;
要返回属性值,请使用不带赋值的圆点表示法:
a.Value
ans =
1.0472
有关类属性的信息,请参阅属性语法。
调用方法
对对象 a
调用 roundOff
方法:
roundOff(a)
ans =
1.0500
将对象作为第一个参数传递给接受多个参数的方法,此处以 multiplyBy
方法的调用为例:
multiplyBy(a,3)
ans =
3.1416
您也可以使用圆点表示法来调用方法:
a.multiplyBy(3)
使用圆点表示法时,没有必要将对象作为参数显式传递。该表示法将对象置于方法名称左侧,用点隔开。
有关类方法的信息,请参阅定义类方法和函数。
添加构造函数
类可以定义一个特殊的方法来创建类对象,称为构造函数。您可以使用构造函数方法将参数传递给构造函数,用以对属性赋值。BasicClass
的 Value
属性使用 mustBeNumeric
函数限制其可能的值。
以下是 BasicClass
类的构造函数。如果在调用构造函数时带有输入参数,此参数会被赋给 Value
属性。如果在调用构造函数时不带输入参数,则 Value
属性采用其默认值,即空 ([]
)。
methods
function obj = BasicClass(val)
if nargin == 1
obj.Value = val;
end
end
end
通过将此构造函数添加到类定义中,只需一个步骤即可创建对象并设置属性值:
a = BasicClass(pi/3)
a =
BasicClass with properties:
Value: 1.0472
构造函数还可以执行与创建类对象相关的其他操作。
有关构造函数的信息,请参阅类构造函数方法。
方法向量化
MATLAB® 支持运算向量化。例如,您可以向向量添加数字:
[1 2 3] + 2
ans =
3 4 5
MATLAB 将数字 2
添加到数组 [1 2 3]
中的每个元素。要向量化算术运算符方法,请将 obj.Value
属性引用括在方括号中。
[obj.Value] + 2
此语法使方法能够处理对象数组。例如,使用索引赋值创建一个对象数组。
obj(1) = BasicClass(2.7984);
obj(2) = BasicClass(sin(pi/3));
obj(3) = BasicClass(7);
则以下表达式:
[obj.Value] + 2
等效于以下表达式:
[obj(1).Value obj(2).Value obj(3).Value] + 2
由于 roundOff
方法是向量化的,因此它可以对数组执行运算:
roundOff(obj)
ans =
2.8000 0.8700 7.0000
重载函数
类可以通过定义与现有 MATLAB 函数同名的方法来实现现有功能,例如加法。例如,假设您要添加两个 BasicClass
对象。这通常意味着将每个对象的 Value
属性的值相加。
下面是 MATLAB plus
函数的重载版本。它将 BasicClass
类的加法定义为属性值相加:
method
function r = plus(o1,o2)
r = [o1.Value] + [o2.Value];
end
end
通过实现名为 plus
的方法,您可以对 BasicClass
的对象使用“+
”运算符。
a = BasicClass(pi/3);
b = BasicClass(pi/4);
a + b
ans =
1.8326
通过向量化 plus 方法,您可以对对象数组执行运算。
a = BasicClass(pi/3);
b = BasicClass(pi/4);
c = BasicClass(pi/2);
ar = [a b];
ar + c
ans =
2.6180 2.3562
相关信息
有关重载函数的信息,请参阅在类定义中重载函数。
有关重载运算符的信息,请参阅运算符重载。
BasicClass
代码列表
以下是添加本主题中讨论的功能后的 BasicClass
定义:
classdef BasicClass
properties
Value {mustBeNumeric}
end
methods
function obj = BasicClass(val)
if nargin == 1
obj.Value = val;
end
end
function r = roundOff(obj)
r = round([obj.Value],2);
end
function r = multiplyBy(obj,n)
r = [obj.Value] * n;
end
function r = plus(o1,o2)
r = [o1.Value] + [o2.Value];
end
end
end
子类定义语法
要定义作为另一个类的子类的类,请将超类添加到 classdef
行中的 <
字符后:
classdef ClassName < SuperClass
从多个类继承时,使用 &
字符来指示超类的组合:
classdef ClassName < SuperClass1 & SuperClass2
有关从多个超类派生的详细信息,请参阅Class Member Compatibility。
类属性
子类不继承超类属性。
子类化 double
假设您要定义从 double
派生的类,并将值限制为正数。PositiveDouble
类:
- 支持默认构造函数(无输入参数)。请参阅构造函数不要求输入参数的情况
- 使用
mustBePositive
将输入限制为正值。 - 用输入值调用超类构造函数来创建双精度数值。
classdef PositiveDouble < double
methods
function obj = PositiveDouble(data)
if nargin == 0
data = 1;
else
mustBePositive(data)
end
obj = obj@double(data);
end
end
end
使用 1×5 数值数组创建 PositiveDouble
类的对象:
a = PositiveDouble(1:5);
您可以像对任何双精度值一样对该类的对象执行运算。
sum(a)
ans =
15
PositiveDouble
类的对象必须为正值。
a = PositiveDouble(0:5);
Error using mustBePositive (line 19)
Value must be positive.
Error in PositiveDouble (line 7)
mustBePositive(data)
Subclassing Multiple Classes(继承多个类)
Specify Multiple Superclasses
When inheriting from multiple classes, use the &
character to indicate the combination of the superclasses:
classdef ClassName < SuperClass1 & SuperClass2
For more information on class syntax, see Subclass Syntax.
Class Member Compatibility
When you create a subclass derived from multiple superclasses, the subclass inherits the properties, methods, and events defined by all specified superclasses. If more than one superclass defines a property, method, or event having the same name, there must be an unambiguous resolution to the multiple definitions. You cannot derive a subclass from any two or more classes that define incompatible class members.
Here are various situations where you can resolve name and definition conflicts.
Property Conflicts
If two or more superclasses define a property with the same name, then at least one of the following must be true:
- All, or all but one of the properties must have their
SetAccess
andGetAccess
attributes set toprivate
- The properties have the same definition in all superclasses (for example, when all superclasses inherited the property from a common base class)
Method Conflicts
If two or more superclasses define methods with the same name, then at least one of the following must be true:
- The method
Access
attribute isprivate
so only the defining superclass can access the method. - The method has the same definition in all subclasses. This situation can occur when all superclasses inherit the method from a common base class and none of the superclasses override the inherited definition.
- The subclass redefines the method to disambiguate the multiple definitions across all superclasses. Therefore, the superclass methods must not have their
Sealed
attribute set totrue
. - Only one superclass defines the method as
Sealed
, in which case, the subclass adopts the sealed method definition. - The superclasses define the methods as
Abstract
and rely on the subclass to define the method.
Event Conflicts
If two or more superclasses define events with the same name, then at least one of the following must be true:
- The event
ListenAccess
andNotifyAccess
attributes must beprivate
. - The event has the same definition in all superclasses (for example, when all superclasses inherited the event from a common base class)
Multiple Inheritance
Resolving the potential conflicts involved when defining a subclass from multiple classes often reduces the value of this approach. For example, problems can arise when you enhance superclasses in future versions and introduce new conflicts.
Reduce potential problems by implementing only one unrestricted superclass. In all other superclasses, all methods are
- Abstract
- Defined by a subclass
- Inherited from the unrestricted superclass
When using multiple inheritance, ensure that all superclasses remain free of conflicts in definition.
Comments NOTHING