目录
类构造函数方法
类构造函数方法的目的
构造函数方法的基本结构
构造函数的指导原则
默认构造函数
何时定义构造函数
初始化构造函数中的对象
构造函数不要求输入参数的情况
子类构造函数
对继承的构造函数的隐式调用
类构造过程中的错误
禁止显示输出对象
构造函数方法是一个创建类实例的特殊函数。通常,构造函数方法接受输入参数来指定存储在属性中的数据,并返回初始化的对象。
所有 MATLAB® 类都有默认的构造函数方法。此方法返回在没有输入参数的情况下创建的类的对象。类可以定义覆盖默认构造函数的构造函数方法。显式定义的构造函数可以接受输入参数、初始化属性值、调用其他方法以及执行创建类对象所需的其他操作。
构造函数方法的结构包含三个基本部分:
初始化前 - 计算超类构造函数的参数。
对象初始化 - 调用超类构造函数。
初始化后 - 执行任何与子类相关的操作,包括对象的引用和赋值、调用类方法、将对象传递给函数等。
以下代码说明在每个部分执行的基本操作:
classdef ConstructorDesign < BaseClass1
properties
ComputedValue
end
methods
function obj = ConstructorDesign(a,b,c)
%% Pre Initialization %%
% Any code not using output argument (obj)
if nargin == 0
% Provide values for superclass constructor
% and initialize other inputs
a = someDefaultValue;
args{1} = someDefaultValue;
args{2} = someDefaultValue;
else
% When nargin ~= 0, assign to cell array,
% which is passed to supclass constructor
args{1} = b;
args{2} = c;
end
compvalue = myClass.staticMethod(a);
%% Object Initialization %%
% Call superclass constructor before accessing object
% You cannot conditionalize this statement
obj = obj@BaseClass1(args{:});
%% Post Initialization %%
% Any code, including access to object
obj.classMethod(arg);
obj.ComputedValue = compvalue;
...
end
...
end
...
end
像调用任何函数一样调用构造函数,传递参数并返回类的对象。
obj = ConstructorDesign(a,b,c);
构造函数与类同名。
构造函数可以返回多个参数,但第一个输出必须为创建的对象。
如果不想对输出参数赋值,可以在构造函数中清除对象变量。
如果创建类构造函数,请确保可以在没有输入参数的情况下调用它。
如果构造函数对超类构造函数进行显式调用,则该调用必须发生在对构造对象的任何其他引用之前,并且不能发生在return语句后。
对超类构造函数的调用不能为条件调用。您不能在循环、条件、switch、try/catch 或嵌套函数中放置超类构造调用。
如果类没有定义构造函数,则 MATLAB 提供默认构造函数,它不接受任何参数,并返回一个标量对象,该对象的属性初始化为属性的默认值。由 MATLAB 提供的默认构造函数也调用所有超类构造函数,其中可以不将任何参数传递给默认子类构造函数,也可以将任何参数传递给默认子类构造函数。
当子类没有定义构造函数时,默认构造函数将其输入传递给直接超类构造函数。当子类不需要定义构造函数而超类构造函数需要输入参数时,此行为很有用。
当需要执行默认构造函数无法执行的对象初始化时,可以定义构造函数方法。例如,当创建类的对象需要:
输入参数时
初始化类的每个实例的对象状态(例如属性值)时
用子类构造函数确定的值调用超类构造函数时
构造函数方法将初始化的对象以输出参数形式返回。输出参数是在构造函数执行时,在执行第一行代码之前创建的。
例如,以下构造函数可以将为对象的属性A的赋值作为第一个语句,因为已将对象obj指定给MyClass的一个实例。
function obj = MyClass(a,b,c)
obj.A = a;
...
end
可以从构造函数调用其他类方法,因为对象已初始化。构造函数还会创建一个对象,该对象的属性具有默认值 - 空值 ([]
) 或属性定义代码块中指定的默认值。
例如,以下构造函数对输入参数进行运算,以为Value属性赋值。
function obj = MyClass(a,b,c)
obj.Value = (a + b) / c;
...
end
在构造函数中引用对象
在初始化对象(例如,通过给属性赋值)时,使用输出参数的名称来引用构造函数中的对象。例如,在以下代码中,输出参数是obj,而对象也被引用为obj:
% obj is the object being constructed
function obj = MyClass(arg)
obj.propert1 = arg*10;
obj.method1;
...
end
在某些情况下,必须能够在没有输入参数的情况下调用构造函数:
将对象加载到工作区时,如果将类的 ConstructOnLoad 属性设置为 true,则 load 函数将不带参数调用类构造函数。
在创建或扩展对象数组时,如果并非所有元素都有特定值,则将以不带参数的方式调用类构造函数来填充未指定的元素(例如,x(10,1) = MyClass(a,b,c);)。在这种情况下,将不带参数调用构造函数一次,以用此对象的副本填充空数组元素 (x(1:9,1))。
如果没有输入参数,构造函数仅使用默认属性值创建对象。最好在类构造函数中添加零参数检查,以防止在出现这两种情况时报错:
function obj = MyClass(a,b,c)
if nargin > 0
obj.A = a;
obj.B = b;
obj.C = c;
...
end
end
子类构造函数可以显式调用超类构造函数来将参数传递给超类构造函数。子类构造函数必须在对超类构造函数的调用中指定这些参数,并且必须使用构造函数输出参数来进行调用。语法如下:
classdef MyClass < SuperClass
methods
function obj = MyClass(a,b,c,d)
obj@SuperClass(a,b);
...
end
end
end
子类构造函数对超类构造函数的所有调用都必须发生在对 (obj) 对象的任何其他引用之前。此限制包括为属性赋值或调用普通类方法。此外,子类构造函数只能调用超类构造函数一次。
仅引用指定的超类
如果classdef没有将类指定为超类,则构造函数将无法使用此语法来调用超类构造函数。也就是说,子类构造函数只能调用classdef 行中列出的直接超类构造函数。
classdef MyClass < SuperClass1 & SuperClass2
MATLAB 按从左到右的顺序调用任何未调用的构造函数,这些构造函数在classdef 行中指定。MATLAB 对这些调用不传递任何参数。
对超类构造函数的无条件调用
对超类构造函数的调用必须为无条件调用。对给定超类只能调用一次。请在使用对象之前调用超类构造函数,以初始化对象的超类部分(例如,为属性赋值或调用类方法)。
要使用依赖于某些条件的不同参数调用超类构造函数,请构建参数的元胞数组,并提供对该构造函数的一次调用。
例如,当不带参数调用 Cube 构造函数时,Cube类构造函数将使用默认值调用超类Shape构造函数。如果使用四个输入参数调用 Cube 构造函数,则会将upvector和viewangle传递给超类构造函数:
classdef Cube < Shape
properties
SideLength = 0
Color = [0 0 0]
end
methods
function cubeObj = Cube(length,color,upvector,viewangle)
% Assemble superclass constructor arguments
if nargin == 0
super_args{1} = [0 0 1];
super_args{2} = 10;
elseif nargin == 4
super_args{1} = upvector;
super_args{2} = viewangle;
else
error('Wrong number of input arguments')
end
% Call superclass constructor
cubeObj@Shape(super_args{:});
% Assign property values if provided
if nargin > 0
cubeObj.SideLength = length;
cubeObj.Color = color;
end
...
end
...
end
end
零个或多个超类参数
要支持不带参数调用超类构造函数的语法,请显式提供以下语法。
假设在 Cube 类示例中,Shape 超类和 Cube 子类中的所有属性值都在类定义中指定了默认值。然后,您可以创建 Cube 的实例,而无需为超类或子类构造函数指定任何参数。
下面说明如何在 Cube 构造函数中实现此行为:
methods
function cubeObj = Cube(length,color,upvector,viewangle)
% Assemble superclass constructor arguments
if nargin == 0
super_args = {};
elseif nargin == 4
super_args{1} = upvector;
super_args{2} = viewangle;
else
error('Wrong number of input arguments')
end
% Call superclass constructor
cubeObj@Shape(super_args{:});
% Assign property values if provided
if nargin > 0
cubeObj.SideLength = length;
cubeObj.Color = color;
end
...
end
end
MATLAB 将参数从默认子类构造函数隐式传递给超类构造函数。这样,就无需仅为了将参数传递给超类构造函数,而为子类实现一个构造函数方法。
例如,以下类构造函数需要输入参数(datatime对象),该参数由构造函数指定给 CurrentDate 属性。
classdef BaseClassWithConstr
properties
CurrentDate datetime
end
methods
function obj = BaseClassWithConstr(dt)
obj.CurrentDate = dt;
end
end
end
假设创建了BaseClassWithConstr的一个子类,但是,子类不需要显式构造函数方法。
classdef SubclassDefaultConstr < BaseClassWithConstr
...
end
可以通过用超类参数调用默认构造函数来构造SubclassDefaultConstr的对象:
obj = SubclassDefaultConstr(datetime);
对于句柄类,在下列情况下出现错误时,MATLAB 会调用delete方法:
在错误发生前,代码中存在对对象的引用。
在错误发生前,代码中存在较早的return语句。
MATLAB 对对象调用delete方法,对属性中包含的任何对象调用delete方法,对任何初始化的基类调用delete方法。
根据错误发生的时间,MATLAB 可以在对象完全构造之前调用类析构函数。
因此,类 delete 方法必须能够对部分构造的对象进行操作,这些对象可能没有所有属性的值。
当在对构造函数的调用中没有指定输出变量时,可以禁止将类实例赋给ans变量。这种编程方式对于创建图形界面窗口的 App 非常有用,这些窗口会保留构造的对象。这些 App 不需要返回对象。
使用nargout来确定是否带输出参数调用了构造函数。例如,如果调用时未指定输出,则 MyApp 类的类构造函数会清除对象变量 obj:
classdef MyApp
methods
function obj = MyApp
...
if nargout == 0
clear obj
end
end
...
end
end
当类构造函数不返回对象时,MATLAB 不会触发meta.class InstanceCreated 事件。