Main Content

类构造函数方法

类构造函数方法的目的

构造函数方法是一个创建类实例的特殊函数。通常,构造函数方法接受输入参数来指定存储在属性中的数据,并返回初始化的对象。

有关基本示例,请参阅创建简单类

未显式定义任何类构造函数的 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.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 构造函数,则会将 upvectorviewangle 传递给超类构造函数:

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 不会触发 meta.class InstanceCreated 事件。

相关主题