Main Content

異種混合配列コンストラクター

スーパークラス コンストラクターでの配列の作成

異種混合クラス階層のサブクラスがそのスーパークラスを呼び出してオブジェクトの配列を作成する場合、スーパークラス コンストラクターが異種混合配列をサブクラスに返さないようにしなければなりません。以下のプログラミング パターンは、正しくないクラスをサブクラス コンストラクターに返すことによって発生するエラーを回避する方法を示します。

エラーが発生する可能性がある状況

コンストラクターは定義クラスと同じクラスのオブジェクトを返さなければなりません。異種混合クラス階層のオブジェクトを扱う場合、異なるクラスの配列要素を追加するとオブジェクト配列のクラスが変わります。このため、クラス設計で以下の手法がすべて必要になる場合、異種混合スーパークラス コンストラクターはオブジェクト配列のクラスを変更する可能性があります。

  • サブクラス コンストラクターでオブジェクト配列を作成する

  • サブクラス コンストラクターからスーパークラス コンストラクターを呼び出して引数を渡す

  • スーパークラス コンストラクターでオブジェクト配列を作成する

さらに、以下のいずれかに該当します。

  • ルート スーパークラスが抽象型ではなく、matlab.mixin.Heterogeneous.getDefaultScalarElement メソッドを実装していない。

  • ルート スーパークラスが、サブクラスと同じクラスではないオブジェクトを返す getDefaultScalarElement メソッドを実装している。

オブジェクト配列への代入を行うときに、MATLAB® は既定のオブジェクトを使用して、代入されていない配列要素を埋めます。異種混合階層では、既定のオブジェクトをサブクラス コンストラクターによって呼び出されるスーパークラスにすることができます。このため、スーパークラス コンストラクターで配列を作成することにより、異種混合配列を作成できます。

スーパークラス コンストラクターがサブクラス コンストラクターに異種混合配列を返すと、MATLAB はエラーを生成します (潜在的なエラーを参照)。

スーパークラス コンストラクターでの配列の初期化

エラーを回避するには、スーパークラス コンストラクターでオブジェクト配列を明示的に初期化します。たとえば、オブジェクトのスーパークラス部分を初期化する前に、スーパークラス コンストラクターで repelem を使用して配列を初期化します。配列の初期化により、配列に代入されたすべての要素が確実に obj 引数と同じクラスになるようにします。

このコードでは、スーパークラス コンストラクターは入力引数 arg の要素ごとに 1 つのオブジェクトを作成します。

methods
   function obj = SuperClass(arg)
      ...
      n = numel(arg);
      obj = repelem(obj,1,n);
      for k = 1:n
         obj(k).SuperProp = arg(k);
      end
      ...
   end
end

サブクラス コンストラクターは、スーパークラス コンストラクターを呼び出して必須の引数配列 a を渡します。

methods
   function obj = SubClass(a)
      obj = obj@SuperClass(a);
      for k = 1:numel(a)
         obj(k).SubProp = a(k);
      end
   end
end

サンプル実装

以下のクラス階層は、コンストラクターでオブジェクト配列を作成するサブクラスを定義します。階層のルート スーパークラスは、配列のオブジェクトのスーパークラス部分を初期化します。

このクラス階層はエンジニアリング チームのメンバーを表します。階層のクラスには、次のものが含まれます。

  • TeamMembersProjectEngineer など、特定のチーム メンバーのクラスのスーパークラス。TeamMembersName プロパティと PhoneX プロパティを定義し、matlab.mixin.Heterogeneous から派生します。

  • ProjectEngineer — エンジニアであるチーム メンバー。各インスタンスは Name プロパティと PhoneX プロパティを継承し、請求の Rate プロパティを定義します。

  • その他のメンバー — 簡略化するため、この例ではその他のチーム メンバーのタイプは実装されません。

Heterogeneous class hierarchy representing engineering team

TeamMembers クラスは異種混合階層のルートであり、具象クラスです。Name プロパティと PhoneX プロパティに値を代入する前に、コンストラクターはサブクラス (ProjectEngineer) オブジェクトの配列を初期化します。

ProjectEngineer コンストラクターは、repelem の呼び出しのために、次のステートメントを使用して obj 引数を提供します。

obj = obj@TeamMembers(varargin{1:2});

TeamMembers クラスは次のようになります。

classdef TeamMembers < matlab.mixin.Heterogeneous
   properties
      Name
      PhoneX
   end
   methods
      function obj = TeamMembers(nme,ext)
         if nargin > 0
            n = numel(nme);
            obj = repelem(obj,1,n);
            for k = 1:n
               obj(k).Name = nme{k};
               obj(k).PhoneX = ext(k);
            end
         else
            obj.Name = '';
         end
      end
   end
end

ProjectEngineer クラスはチーム メンバーの 1 つのタイプを表します。このクラスは配列入力をサポートし、オブジェクトの配列を返します。

classdef ProjectEngineer < TeamMembers
   % Inputs: {Name}, [PhoneX], {Rate}
   properties
      Rate
   end
   methods
      function obj = ProjectEngineer(varargin)
         obj = obj@TeamMembers(varargin{1:2});
         for k = 1:numel(varargin{1})
            obj(k).Rate = varargin{3}{k};
         end
      end
   end
end

ProjectEngineer クラスでは、チーム内のエンジニアごとに、名前の cell 配列、内線電話番号の数値配列、および請求料率の cell 配列が必要です。

nm = {'Fred','Nancy','Claudette'};
px = [8112,8113,8114];
rt = {'C2','B1','A2'};
tm = ProjectEngineer(nm,px,rt)
tm = 

  1x3 ProjectEngineer array with properties:

    Rate
    Name
    PhoneX

潜在的なエラー

TeamMembers コンストラクターは、次のステートメントを使用してオブジェクト配列を初期化します。

obj = repelem(obj,1,n);

repelemobj 引数は ProjectEngineer オブジェクトであるため、返される配列は同じクラスになります。

このステートメントを使用しないと、TeamMembers コンストラクターは既定のオブジェクトを作成して for ループで配列要素を埋めます。結果として得られる異種混合配列は、共通スーパークラス (この場合は TeamMembers) のクラスになります。スーパークラスがこの異種混合配列をサブクラス コンストラクターに返すと、クラス コンストラクターは返されたオブジェクトのクラスを保持しなければならないというルールの違反になります。

MATLAB は次のエラーを発行します。

When constructing an instance of class 'ProjectEngineer', the constructor must
preserve the class of the returned object.

Error in ProjectEngineer (line 8)
         obj = obj@TeamMembers(varargin{1:2});

関連するトピック