This is machine translation

Translated by Microsoft
Mouse over text to see original. Click the button below to return to the English verison of the page.

Support Both Handle and Value Subclasses

Basic Knowledge

The material presented in this section builds on knowledge of the following information.

Key Concepts

Handle-compatible class is a class that you can combine with handle classes when defining a set of superclasses.

  • 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.

Handle Compatibility Rules

Handle-compatible classes (that is, classes whose HandleCompatible attribute 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 HandleCompatibility attribute to false, then none of the class superclasses can be handle classes.

  • If a class does not explicitly set its HandleCompatible attribute and, if any superclass is a handle, then all superclasses must be handle compatible.

  • The HandleCompatible attribute is not inherited.

A class that does not explicitly set its HandleCompatible attribute to true is:

  • A handle class if any of its superclasses are handle classes

  • A value class if none of the superclasses are handle classes

Define Handle-Compatible Classes

A class is handle compatible if:

  • It is a handle class

  • Its HandleCompatible attribute is set to true

The 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.

A Handle Compatible Class

The Utility class is useful to both handle and value subclasses. In this example, the Utility class defines a method to reset property values to the default values defined in the respective class definition:

classdef (HandleCompatible) Utility
      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;

The 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.

Return Modified Objects

The resetDefaults method defined by the Utility class returns the object it modifies. When you call resetDefaults with 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 Utility class. The PropertyDefaults class defines three properties, all of which have default values:

classdef PropertyDefaults < Utility
      p1 = datestr(rem(now,1)); % Current time
      p2 = 'red';               % Character vector
      p3 = pi/2;                % Result of division operation

Create a 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;

All 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

Call the resetDefaults method, which is inherited from the Utility class. Because the PropertyDefaults class 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

If the PropertyDefaults class was a handle class, then you would not need to save the object returned by the resetDefaults method. To design a handle compatible class like Utility, ensure that all methods work with both kinds of classes.

Subclass Handle-Compatible 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.

Combine Nonhandle Utility Class with Handle Classes

Suppose that you define a class that subclasses a handle class, and the handle compatible Utility class discussed in A Handle Compatible Class. The HPropertyDefaults class has these characteristics:

  • It is a handle class (it derives from handle).

  • All its superclasses are handle compatible (handle classes are handle compatible by definition).

classdef HPropertyDefaults < handle & Utility
      GraphPrim = line;
      Width = 1.5;
      Color = 'black';

The HPropertyDefaults class is handle compatible:

hpd = HPropertyDefaults;
mc = metaclass(hpd);
ans =


Nonhandle Subclasses of a Handle-Compatible Class

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 ValueSub class:

  • Is a value class (It does not derive from handle.)

  • One of its superclasses is handle compatible (the Utility class).

classdef ValueSub < MException & Utility
      function obj = ValueSub(str1,str2)
         obj = obj@MException(str1,str2);

The ValueSub class is a nonhandle-compatible value class because the MException class does not define the HandleCompatible attribute as true:

hv = ValueSub('MATLAB:narginchk:notEnoughInputs',...
      'Not enough input arguments.');
mc = metaclass(hv);
ans =


Methods for Handle Compatible Classes

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.

Identify Handle Objects

To determine if an object is a handle object, use the isa function:


Modify Value Objects in Methods

If a method operates on both handle and value objects, the method must return the modified object. For example, the setTime method returns the object it modifies:

classdef (HandleCompatible) Util
   % Utility class that adds a time stamp
      function obj = setTime(obj)
         obj.TimeStamp = now;

Handle-Compatible Classes and Heterogeneous Arrays

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 matlab.mixin.Heterogeneous class for more information on heterogeneous arrays. The matlab.mixin.Heterogeneous class is a handle-compatible class.

Methods Must Be Sealed

You can invoke only those methods that are sealed by the common superclass on heterogeneous arrays (Sealed attribute set to 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.

Template Technique

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.

The Printable class shows how to implement a template method approach:

classdef (HandleCompatible) Printable
      function print(aryIn)
         n = numel(aryIn);
         for k=1:n
   methods(Access=protected, Abstract)

More About

Was this topic helpful?