10

2 つの新しいスタイルの MATLAB クラスB&Cがあります。どちらも抽象的な親の具体的なサブクラスですA。 (ハンドル クラス)Aのサブクラスです。それらをMATLABの配列に入れ、両方をshgsetsetとして扱いたいと思います。Aそれらは、大まかに次のように定義されます。

classdef A <hgsetget
methods
    function foo(this)
        %does some common stuff, then
        this.fooWorker;
    end
end %public Methods
methods(Abstract, Access=protected)
    fooWorker(this);
end %abstract Methods;
end

classdef B < A
methods(Access=protected)
    function fooWorker(this)
        %implementation
    end
end %protected Methods;
end

ただし、これを行うと:

arr = [b c]; % where b & c are objects of type B & C respectively.
arr(1).foo;
arr(2).foo;

MATLAB は、両方とも型が であると教えてくれます。その両方の implement( )Bから抽象メソッドを呼び出すと、基本的に の 2 つのコピーが実行されます。 Afoob

ただし、順序を逆にすると:

arr = [c b];

どちらもタイプCであることがわかり、両方で foo を実行しようとすると、基本的に の 2 つのコピーが実行されcます。

ポリモーフィックな方法でサブクラスを使用する方法はありますか?

それらをセル配列に入れれば、必要なものの 90% を取得できることがわかっています。しかし、それはちょっとしたコツです。

4

2 に答える 2

5

残念ながら、MATLABの配列のすべての要素は同じタイプである必要があります。異なるクラスを連結すると、MATLABはそれらすべてを同じクラスに変換しようとします。

クラスの1つを他のクラスよりも劣っているまたは優れていると定義した場合(InferiorClasses属性またはINFERIORTO / SUPERIORTO関数を使用)、より優れたクラスのメソッドが呼び出されます。クラス間の関係を指定していない場合、2つのオブジェクトの優先順位は等しくなり、MATLABは左端のオブジェクトメソッドを呼び出します。arr = [b c];これが、クラスBの配列をarr = [c b];作成し、クラスCの配列を作成する理由である可能性があります。

オプション1:セルアレイ

fooオブジェクトのクラスBに定義されたメソッドを実行し、オブジェクトのクラスCに定義されbたメソッドも実行する場合は、セル配列と関数CELLFUNを使用する必要があります。が値を返さない場合は、次のようにすることができます。foocfoo

arr = {b,c};
cellfun(@foo,arr);  % Invoke foo on each element of the cell array

オプション2:仮帆装のポリモーフィックな振る舞いを楽しむ

楽しみのために、私は技術的には機能するが、いくつかの制限がある潜在的な解決策を思いついた。アイデアを説明するために、質問にリストしたものと同様のサンプルクラスをいくつかまとめました。これが抽象的なスーパークラスclassAです:

classdef classA < hgsetget
  properties
    stuff
  end
  properties (Access = protected)
    originalClass
  end
  methods
    function foo(this)
      disp('I am type A!');
      if ~strcmp(class(this),this.originalClass)
        this = feval(this.originalClass,this);
      end
      this.fooWorker;
    end
  end
  methods (Abstract, Access = protected)
    fooWorker(this);
  end
end

そして、これがサブクラスの例ですclassB(どこでも置き換えられたものclassCとまったく同じであり、その逆も同様です)。BC

classdef classB < classA
  methods
    function this = classB(obj)
      switch class(obj)
        case 'classB'  % An object of classB was passed in
          this = obj;
        case 'classC'  % Convert input from classC to classB
          this.stuff = obj.stuff;
          this.originalClass = obj.originalClass;
        otherwise      % Create a new object
          this.stuff = obj;
          this.originalClass = 'classB';
      end
    end
  end
  methods (Access = protected)
    function fooWorker(this)
      disp('...and type B!');
    end
  end
end

classBおよびのコンストラクターはclassC、2つのクラスを相互に変換できるように設計されています。プロパティoriginalClassは作成時に初期化され、オブジェクトの元のクラスが何であったかを示します。オブジェクトがあるクラスから別のクラスに変換されても、このプロパティは変更されません。

メソッド内で、foo渡されたオブジェクトの現在のクラスが元のクラスと照合されます。それらが異なる場合、fooWorkerメソッドを呼び出す前に、オブジェクトは最初に元のクラスに変換されます。テストは次のとおりです。

>> b = classB('hello');  % Create an instance of classB
>> c = classC([1 2 3]);  % Create an instance of classC
>> b.foo  % Invoke foo on b
I am type A!
...and type B!
>> c.foo  % Invoke foo on c
I am type A!
...and type C!
>> arr = [b c]  % Concatenate b and c, converting both to classB

arr = 

  1x2 classB handle

  Properties:
    stuff

  Methods, Events, Superclasses

>> arr(1).foo  % Invoke foo on element 1 (formerly b)
I am type A!
...and type B!
>> arr(2).foo  % Invoke foo on element 2 (formerly c)
I am type A!
...and type C!

(少し醜いことを除いて)1つの重要な制限はclassBclassCそれぞれが他にはないプロパティを持っている場合です。このような場合、他のクラスに変換してから元に戻すと、それらのプロパティが失われる可能性があります(つまり、デフォルト値にリセットされます)。ただし、一方のクラスがもう一方のクラスのサブクラスであり、すべて同じプロパティを持ち、それからいくつかの場合、解決策があります。サブクラスをスーパークラスよりも優れているように設定して(上記の説明を参照)、2つのクラスのオブジェクトを連結すると、常にスーパークラスオブジェクトがサブクラスに変換されます。(上記のような)「ポリモーフィック」メソッド内で変換して戻すfooと、オブジェクトデータが失われることはありません。

これがどれほど実行可能な解決策であるかはわかりませんが、少なくともいくつかの興味深いアイデアが得られるかもしれません。;)

于 2009-09-22T05:38:20.350 に答える