異種混合配列コンストラクター
スーパークラス コンストラクターでの配列の作成
異種混合クラス階層のサブクラスがそのスーパークラスを呼び出してオブジェクトの配列を作成する場合、スーパークラス コンストラクターが異種混合配列をサブクラスに返さないようにしなければなりません。以下のプログラミング パターンは、正しくないクラスをサブクラス コンストラクターに返すことによって発生するエラーを回避する方法を示します。
エラーが発生する可能性がある状況
コンストラクターは定義クラスと同じクラスのオブジェクトを返さなければなりません。異種混合クラス階層のオブジェクトを扱う場合、異なるクラスの配列要素を追加するとオブジェクト配列のクラスが変わります。このため、クラス設計で以下の手法がすべて必要になる場合、異種混合スーパークラス コンストラクターはオブジェクト配列のクラスを変更する可能性があります。
サブクラス コンストラクターでオブジェクト配列を作成する
サブクラス コンストラクターからスーパークラス コンストラクターを呼び出して引数を渡す
スーパークラス コンストラクターでオブジェクト配列を作成する
さらに、以下のいずれかに該当します。
ルート スーパークラスが抽象型ではなく、
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
サンプル実装
以下のクラス階層は、コンストラクターでオブジェクト配列を作成するサブクラスを定義します。階層のルート スーパークラスは、配列のオブジェクトのスーパークラス部分を初期化します。
このクラス階層はエンジニアリング チームのメンバーを表します。階層のクラスには、次のものが含まれます。
TeamMembers
—ProjectEngineer
など、特定のチーム メンバーのクラスのスーパークラス。TeamMembers
はName
プロパティとPhoneX
プロパティを定義し、matlab.mixin.Heterogeneous
から派生します。ProjectEngineer
— エンジニアであるチーム メンバー。各インスタンスはName
プロパティとPhoneX
プロパティを継承し、請求のRate
プロパティを定義します。その他のメンバー — 簡略化するため、この例ではその他のチーム メンバーのタイプは実装されません。
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);
repelem
の obj
引数は 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});