The material presented in this section builds on knowledge of the following information.
Handle-compatible class — a class that you can include with handle classes in a class hierarchy, even if the class is not a handle class.
All handle classes are handle-compatible.
All superclasses of handle-compatible classes must also be handle compatible.
HandleCompatible — the class attribute
that defines nonhandle classes as handle compatible.
Typically, when deriving a MATLAB® class from other classes, all the superclasses are handle classes, or else none of them are handle classes. However, there are situations in which a class provides some utility that is used by both handle and non-handle subclasses. Because it is not legal to combine handle and non-handle classes, the author of the utility class must implement two distinct versions of the utility.
The solution is to use handle-compatible classes. Handle compatible
classes are a type of class that you can use with handle classes when
forming sets of superclasses. Designate a nonhandle compatible class
as handle-compatible by using the
classdef (HandleCompatible) MyClass ... end
Handle-compatible classes (that is, classes whose
is set to
true) follow these rules:
All superclasses of a handle-compatible class must also be handle compatible
If a class explicitly sets its
false, then none of the class superclasses can
be handle classes.
If a class does not explicitly set its
and, if any superclass is a handle, then all superclasses must be
is not inherited.
A class that does not explicitly set its
A handle class if any of its superclasses are handle classes
A value class if none of the superclasses are handle classes
A class is handle compatible if:
It is a handle class
is set to
HandleCompatible class attribute identifies
classes that you can combine with handle classes when specifying a
set of superclasses.
Handle compatibility provides greater flexibility when defining abstract superclasses. For example, mixin and interface classes in which the superclass supports both handle and value subclasses. Handle compatibility removes the need to define both a handle version and a nonhandle version of a class.
Utility class is useful to both handle
and value subclasses. In this example, the
defines a method to reset property values to the default values defined
in the respective class definition:
classdef (HandleCompatible) Utility methods function obj = resetDefaults(obj) mc = metaclass(obj); mp = mc.PropertyList; for k=1:length(mp) if mp(k).HasDefault && ~strcmp(mp(k).SetAccess,'private') obj.(mp(k).Name) = mp(k).DefaultValue; end end end end end
Utility class is handle compatible. Therefore,
you can use it in the derivation of classes that are either handle
classes or value classes. See Class Metadata for
information on using meta-data classes.
resetDefaults method defined by the
returns the object it modifies. When you call
a value object, the method must return the modified object. It is
important to implement methods that work with both handle and value
objects in a handle compatible superclass. See Object Modification for more information on modifying handle
and value objects.
Consider the behavior of a value class that subclasses the
PropertyDefaults class defines three properties,
all of which have default values:
classdef PropertyDefaults < Utility properties p1 = datestr(rem(now,1)) % Current time p2 = 'red' % Character vector p3 = pi/2 % Result of division operation end end
PropertyDefaults object. MATLAB evaluates
the expressions assigned as default property values when the class
is first loaded. MATLAB uses these same default values whenever
you create an instance of this class in the current MATLAB session.
pd = PropertyDefaults
pd = PropertyDefaults with properties: p1: ' 4:42 PM' p2: 'red' p3: 1.5708
Assign new values that are different from the default values:
pd.p1 = datestr(rem(now,1)); pd.p2 = 'green'; pd.p3 = pi/4;
pd object property values now contain
values that are different from the default values originally defined
by the class:
pd = PropertyDefaults with properties: : p1: ' 4:45 PM' p2: 'green' p3: 0.7854
resetDefaults method, which is inherited
Utility class. Because the
is not a handle class, return the modified object.
pd = pd.resetDefaults
pd = PropertyDefaults with properties: p1: ' 4:54 PM' p2: 'red' p3: 1.5708
PropertyDefaults class was a handle
class, then you would not need to save the object returned by the
To design a handle compatible class like
ensure that all methods work with both kinds of classes.
According to the rules described in Handle Compatibility Rules, when you combine a handle superclass with a handle-compatible superclass, the result is a handle subclass, which is handle compatible.
However, subclassing a handle-compatible class does not necessarily result in the subclass being handle compatible. Consider the following two cases, which demonstrate two possible results.
Suppose that you define a class that subclasses a handle class,
and the handle compatible
Utility class discussed
in A Handle Compatible Class. The
has these characteristics:
It is a handle class (it derives from
All its superclasses are handle compatible (handle classes are handle compatible by definition).
classdef HPropertyDefaults < handle & Utility properties GraphPrim = line Width = 1.5 Color = 'black' end end
HPropertyDefaults class is handle compatible:
hpd = HPropertyDefaults; mc = metaclass(hpd); mc.HandleCompatible
ans = 1
If you subclass both a value class that is not handle compatible
and a handle compatible class, the subclass is a nonhandle compatible
value class. The
Is a value class (It does not derive from
One of its superclasses is handle compatible (the
classdef ValueSub < MException & Utility methods function obj = ValueSub(str1,str2) obj = obj@MException(str1,str2); end end end
ValueSub class is a nonhandle-compatible
value class because the
does not define the
hv = ValueSub('MATLAB:narginchk:notEnoughInputs',... 'Not enough input arguments.'); mc = metaclass(hv); mc.HandleCompatible
ans = 0
Objects passed to methods of handle compatible classes can be either handle or value objects. There are two different behaviors to consider when implementing methods for a class that operate on both handles and values:
If an input object is a handle object and the method alters the handle object, these changes are visible to all workspaces that contain the same handle.
If an input object is a value object, then changes to the object made inside the method affect only the value inside the method workspace.
Handle compatible methods generally do not alter input objects because the effects of such changes are not the same for handle and nonhandle objects.
See Object Modification for information about modifying handle and value objects.
To determine if an object is a handle object, use the
If a method operates on both handle and value objects, the method
must return the modified object. For example, the
returns the object it modifies:
classdef (HandleCompatible) Util % Utility class that adds a time stamp properties TimeStamp end methods function obj = setTime(obj) obj.TimeStamp = now; end end end
A heterogeneous array contains objects of different classes.
Members of a heterogeneous array have a common superclass, but can
belong to different subclasses. See the
for more information on heterogeneous arrays. The
is a handle-compatible class.
You can invoke only those methods that are sealed by the common
superclass on heterogeneous arrays (
true). Sealed methods prevent subclasses
from overriding those methods and guarantee that methods called on
heterogeneous arrays have the same definition for the entire array.
Subclasses cannot override sealed methods. In situations requiring subclasses to specialize methods defined by a utility class, you can employ the design pattern referred to as the template method.
Suppose that you implement a handle compatible class that works with heterogeneous arrays. This approach enables you to seal public methods, while providing a way for each subclass to specialize how the method works on each subclass instance. In the handle compatible class:
Define a sealed method that accepts a heterogeneous array as input.
Define a protected, abstract method that each subclass must implement.
Within the sealed method, call the overridden method for each array element.
Each subclass in the heterogeneous hierarchy implements a concrete version of the abstract method. The concrete method provides specialized behavior required by the particular subclass.
Printable class shows how to implement
a template method approach:
classdef (HandleCompatible) Printable methods(Sealed) function print(aryIn) n = numel(aryIn); for k=1:n printElement(aryIn(k)); end end end methods(Access=protected, Abstract) printElement(objIn) end end