目录
类成员访问
基础知识
访问控制列表的应用
控制对类成员的访问
具有访问列表的属性
具有访问列表的方法
具有访问列表的抽象方法
要学习本节的材料,需要具备以下前提知识:
类成员 - 由类定义的属性、方法和事件
定义类 - 该类定义要为其指定访问权限的类成员
获取访问权限 - 读取属性值的权限,由属性 GetAccess 特性控制
设置访问权限 - 为属性赋值的权限;由属性 SetAccess 特性控制
方法访问 - 确定哪些其他方法和函数可以调用类方法;由方法 Access 属性控制
侦听访问权限 - 定义侦听程序的权限;由事件 ListenAccess 属性控制
通知访问权限 - 触发事件的权限,由事件 NotifyAccess 属性控制
访问类成员的可能值
下列类成员属性可以包含类列表:
属性 - Access、GetAccess 和 SetAccess。有关所有属性特性的列表,可以参考属性特性。
方法 - Access。有关所有方法属性的列表,可以参考方法特性。
事件 - ListenAccess 和 NotifyAccess。
这些属性接受以下可能的值:
public - 不受限制的访问
protected - 可由定义类及其子类进行访问
private - 仅由定义类进行访问
访问列表 - 一个或多个类的列表。只有定义类和列表中的类才能访问该属性所应用到的类成员。如果指定了类列表,MATLAB® 不允许任何其他类访问(即访问权限为 private,但列出的类除外)。
访问控制列表可用于控制对特定类属性、方法和事件的访问。可使用访问控制列表来指定类列表,向列表中的类授予对这些类成员的访问权限。
这种方式在类系统的设计中提供了更大的灵活性和更强的控制。例如,使用访问控制列表定义不同的类列表,但不允许从类系统外访问类成员。
在成员访问属性语句中指定允许访问特定类成员的类。例如:
methods (Access = {?ClassName1,?ClassName2,...})
请使用类 meta.class 对象来引用访问列表中的类。要指定多个类,可使用 meta.class 对象的元胞数组。引用包中的类时,需要使用包名称。
注意:请显式指定 meta.class 对象(使用 ? 运算符创建),不能通过函数或其他 MATLAB 表达式的返回值来指定。
MATLAB 如何解释特性值
将访问权限授予类列表时,仅以下类可获取访问权:
定义类
列表中的类
列表中类的子类
如果访问列表中包含定义类,则会为该定义类的所有子类都提供访问权。
访问列表中的类必须先被加载,MATLAB 才会解析对它的引用。如果 MATLAB 找不到访问列表中包含的类,则实际上相当于删除了该类的访问权限。
MATLAB 会用空的 meta.class 对象替换列表中未解析的 meta.class 条目。
空访问列表(即空元胞数组)等效于 private 访问。
指定元类对象
仅使用 ? 运算符和类名生成 meta.class 对象。赋予特性的值不能包含任何其他 MATLAB 表达式,包括可返回允许的特性值的函数:
meta.class 对象
meta.class 对象构成的元胞数组
值 public、protected 或 private
需要显式指定这些值,如本节的示例代码所示。
这些示例类显示授予类读取权限 (GetAccess) 的属性的行为。GrantAccess 类将 Prop1 属性的 GetAccess 授予 NeedAccess 类 :
classdef GrantAccess
properties (GetAccess = ?NeedAccess)
Prop1 = 7
end
end
NeedAccess 类定义一个使用GrantAccess 的 Prop1值的方法。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
由于 AcListNonSub 在 m1 的访问列表中,因此其方法可以使用 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 方法调用 AcListSuper 和 m1 方法:
b.nonSub1(a);
Method m1 called
调用 AcListNonSub 的 m1 方法:
b.m1;
Method m1 defined by AcListNonSub
无访问权限的子类
如果方法的访问列表包含定义类,则从该类派生的所有子类都将被授予访问权。如果子类派生自的类的方法的访问列表不包括定义类, 则:
子类方法无法调用超类方法。
子类方法可以使用访问列表中的类实例间接调用超类方法。
子类无法覆盖超类方法。
超类方法访问列表中所含的非子类的类的方法可以调用超类方法。
例如,AcListSub 是 AcListSuper 的子类。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;
间接调用超类方法
可以使用超类方法的访问列表中某个类的对象,从无权访问超类方法的子类调用超类方法。
AcListSub 的 sub2 方法调用 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 的方法的类是抽象类。子类负责使用在类定义中声明的函数签名实现抽象方法。
当抽象方法有访问列表时,只有访问列表中的类才能实现该方法。不在访问列表中的子类无法实现抽象方法,因此子类本身是抽象类。