类构造函数方法
类构造函数方法的目的
构造函数方法是一个创建类实例的特殊函数。通常,构造函数方法接受输入参量来指定存储在属性中的数据,并返回初始化的对象。
有关基本示例,请参阅创建简单类。
未显式定义任何类构造函数的 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 提供的默认构造函数也调用所有超类构造函数,其中可以不将任何参量传递给默认子类构造函数,也可以将任何参量传递给默认子类构造函数。
当子类没有定义构造函数时,默认构造函数将其输入传递给直接超类构造函数。当子类不需要定义构造函数而超类构造函数需要输入参量时,此行为很有用。
何时定义构造函数
当需要执行默认构造函数无法执行的对象初始化时,可以定义构造函数方法。例如,当创建类的对象需要:
输入参量时
初始化类的每个实例的对象状态(例如属性值)时
用子类构造函数确定的值调用超类构造函数时
相关信息
有关构造枚举的特定信息,请参阅枚举类构造函数调用顺序。
有关在构造函数中创建对象数组的信息,请参阅创建和初始化对象数组。
如果正在创建的类是子类,则 MATLAB 会调用每个超类的构造函数来初始化对象。对超类构造函数的隐式调用不带参量。如果超类构造函数需要参量,请从子类构造函数显式调用它们。请参阅Control Sequence of Constructor Calls
初始化构造函数中的对象
构造函数方法将初始化的对象以输出参量形式返回。输出参量是在构造函数执行时,在执行第一行代码之前创建的。
例如,以下构造函数可以将为对象的属性 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.property1 = arg*10; obj.method1; ... end
有关定义默认属性值的详细信息,请参阅Define Properties with Default Values。
使用名称-值参量设置属性
初始化对象时,可以使用 structName
.?ClassName
语法以允许将属性值作为名称-值参量传入。例如,NameValueClass
构造函数将所有传递的参量收集到结构体 opts
中,然后使用 for
循环来设置属性值。
classdef NameValueClass properties Property1 Property2 end properties (SetAccess=immutable) ImmProperty end methods function obj = NameValueClass(opts) arguments opts.?NameValueClass end for prop = string(fieldnames(opts))' obj.(prop) = opts.(prop); end end end end
调用类构造函数并使用名称-值语法设置 ImmProperty
。
x = NameValueClass(ImmProperty=1)
x = NameValueClass with properties: Property1: [] Property2: [] ImmProperty: 1
有关在函数中使用类属性作为名称-值参量的详细信息,请参阅基于类属性的名称-值参量。
在 R2024a 之前: structName
.?ClassName
语法不适用于不可变 (immutable) 属性。要在以前的版本中使用这种方法,请使用单独的一行来定义与不可变 (immutable) 属性匹配的名称-值参量。例如,在 NameValueClass
中:arguments
opts.ImmProperty
opts.?NameValueClass
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 将参量从默认子类构造函数隐式传递给超类构造函数。这样,就无需仅为了将参量传递给超类构造函数,而为子类实现一个构造函数方法。
例如,以下类构造函数需要输入参量(datetime
对象),该参量由构造函数指定给 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 不会触发 matlab.metadata.Class
InstanceCreated
事件。