Main Content

类成员访问

基础知识

要学习本节的材料,需要预先了解以下概念:

 术语和概念

 访问类成员的可能值

访问控制列表的应用

访问控制列表可用于控制对特定类属性、方法和事件的访问。您可使用访问控制列表来指定类列表,向列表中的类授予对这些类成员的访问权限。

这种方式在类系统的设计中提供了更大的灵活性和更强的控制。例如,使用访问控制列表定义不同的类列表,但不允许从类系统外访问类成员。

控制对类成员的访问

在成员访问属性语句中指定允许访问特定类成员的类。例如:

methods (Access = {?ClassName1,?ClassName2,...})

请使用类 matlab.metadata.Class 对象来引用访问列表中的类。要指定多个类,可使用 matlab.metadata.Class 对象的元胞数组。引用命名空间中的类时,需要使用命名空间名称。

注意

请显式指定 matlab.metadata.Class 对象(使用 ? 运算符创建),不能通过函数或其他 MATLAB 表达式的返回值来指定。

MATLAB 如何解释特性值

  • 将访问权限授予类列表时,仅以下类可获取访问权:

    • 定义类

    • 列表中的类

    • 列表中类的子类

  • 如果访问列表中包含定义类,则会为该定义类的所有子类都提供访问权。

  • 访问列表中的类必须先被加载,MATLAB 才会解析对它的引用。如果 MATLAB 找不到访问列表中包含的类,则实际上相当于删除了该类的访问权限。

  • MATLAB 会用空的 matlab.metadata.Class 对象替换列表中未解析的 matlab.metadata.Class 条目。

  • 空访问列表(即空元胞数组)等效于 private 访问。

指定元类对象

仅使用 ? 运算符和类名生成 matlab.metadata.Class 对象。赋予特性的值不能包含任何其他 MATLAB 表达式,包括可返回允许的特性值的函数:

  • matlab.metadata.Class 对象

  • matlab.metadata.Class 对象构成的元胞数组

  • publicprotectedprivate

需要显式指定这些值,如本节的示例代码所示。

具有访问列表的属性

这些示例类显示授予类读取权限 (GetAccess) 的属性的行为。GrantAccess 类将 Prop1 属性的 GetAccess 授予 NeedAccess 类 :

classdef GrantAccess
   properties (GetAccess = ?NeedAccess)
      Prop1 = 7
   end
end

NeedAccess 类定义一个使用 GrantAccessProp1 值的方法。dispObj 方法定义为 Static 方法,但是,它可能是一个普通方法。

classdef NeedAccess
   methods (Static)
      function dispObj(GrantAccessObj)
         disp(['Prop1 is: ',num2str(GrantAccessObj.Prop1)])
      end
   end
end

Prop1 的访问权限是私有访问权,因此如果您尝试从类定义之外访问该属性,MATLAB 将返回错误。例如,从命令行:

a = GrantAccess;
a.Prop1
Getting the 'Prop1' property of the 'GrantAccess' class is not allowed.

但是,MATLAB 允许 NeedAccess 类访问 Prop1

NeedAccess.dispObj(a)
Prop1 is: 7

具有访问列表的方法

授予类访问方法的权限后,该类可以:

  • 使用定义类的实例调用方法。

  • 用相同的名称定义自己的方法(如果不是子类)。

  • 覆盖子类中的方法(仅当定义方法的超类在访问列表中包含自身或子类时)。

以下示例类说明从访问列表中其他类的方法调用的方法的行为。AcListSuper 类授予 AcListNonSub 类访问其 m1 方法的权限:

classdef AcListSuper
   methods (Access = {?AcListNonSub})
      function obj = m1(obj)
         disp ('Method m1 called')
      end
   end
end

由于 AcListNonSubm1 的访问列表中,因此其方法可以使用 AcListSuper 的实例调用 m1

classdef AcListNonSub
   methods
      function obj = nonSub1(obj,AcListSuper_Obj)
         % Call m1 on AcListSuper class
         AcListSuper_Obj.m1;
      end
      function obj = m1(obj)
         % Define a method named m1
         disp(['Method m1 defined by ',class(obj)])
      end
   end
end

创建两个类的对象:

a = AcListSuper;
b = AcListNonSub;

使用 AcListNonSub 方法调用 AcListSuperm1 方法:

b.nonSub1(a);
Method m1 called

调用 AcListNonSubm1 方法:

b.m1;
Method m1 defined by AcListNonSub

无访问权限的子类

如果方法的访问列表包含定义类,则从该类派生的所有子类都将被授予访问权。如果子类派生自的类的方法的访问列表包括定义类, 则:

  • 子类方法无法调用超类方法。

  • 子类方法可以使用访问列表中的类实例间接调用超类方法。

  • 子类无法覆盖超类方法。

  • 超类方法访问列表中所含的非子类的类的方法可以调用超类方法。

例如,AcListSubAcListSuper 的子类。AcListSuper 类定义方法 m1 的访问列表。但是,该列表不包括 AcListSuper,因此 AcListSuper 的子类无权访问方法 m1

classdef AcListSub < AcListSuper
   methods
      function obj = sub1(obj,AcListSuper_Obj)
         % Access m1 via superclass object (***NOT ALLOWED***)
         AcListSuper_Obj.m1;
      end
      function obj = sub2(obj,AcListNonSub_Obj,AcListSuper_obj)
         % Access m1 via object that is in access list (is allowed)
         AcListNonSub_Obj.nonSub1(AcListSuper_Obj);
      end
   end
end

不能直接调用超类方法

尝试从 sub1 方法调用超类的 m1 方法会导致错误,因为子类不在 m1 的访问列表中:

a = AcListSuper;
c = AcListSub;
c.sub1(a);
Cannot access method 'm1' in class 'AcListSuper'.

Error in AcListSub/sub1 (line 4)
         AcListSuper_Obj.m1;

间接调用超类方法

您可以使用超类方法的访问列表中某个类的对象,从无权访问超类方法的子类调用超类方法。

AcListSubsub2 方法调用 m1 访问列表中某个类 (AcListNonSub) 的方法。此方法 nonSub1 可以访问超类 m1 方法:

a = AcListSuper;
b = AcListNonSub;
c = AcListSub;
c.sub2(b,a);
Method m1 called

不能重新定义超类方法

当方法的访问列表中没有子类时,这些子类无法定义同名的方法。此行为与方法的 Access 明确声明为 private 的情况不同。

例如,向 AcListSub 类定义中添加以下方法会在您尝试实例化该类时产生错误。

methods (Access = {?AcListNonSub})
   function obj = m1(obj)
      disp('AcListSub m1 method')
   end
end
c = AcListSub;
Class 'AcListSub' is not allowed to override the method 'm1' because neither it nor its
superclasses have been granted access to the method by class 'AcListSuper'.

从列表中的非子类通过子类调用超类

AcListNonSub 类位于 m1 方法访问列表中。该类可以使用 AcListSub 类的对象定义调用 m1 方法的方法。虽然 AcListSub 不在方法 m1 的访问列表中,但它是 AcListSuper 的子类。

例如,将以下方法添加到 AcListNonSub 类中:

methods
   function obj = nonSub2(obj,AcListSub_Obj)
      disp('Call m1 via subclass object:')
      AcListSub_Obj.m1;
   end
end

调用 nonSub2 方法会导致执行超类的 m1 方法:

b = AcListNonSub;
c = AcListSub;
b.nonSub2(c);
Call m1 via subclass object:
Method m1 called

此行为与任何子类对象的行为是一致的,子类对象可以替代其超类的对象。

具有访问列表的抽象方法

包含声明为 Abstract 的方法的类是抽象类。子类负责使用在类定义中声明的函数签名实现抽象方法。

当抽象方法有访问列表时,只有访问列表中的类才能实现该方法。不在访问列表中的子类无法实现抽象方法,因此子类本身是抽象类。

相关主题