34.5 Inheritance and Aggregation

Last-modified: 2025-03-09 (日) 08:58:56

34.5 継承と集約

クラスを使用して新しいクラスを構築することは、継承と集約の両方を使用することで Octave によってサポートされています。

クラスの継承は、クラス コンストラクタの関数を使用して Octave によって提供されますclass。多項式クラスの場合と同様に、Octave プログラマーはクラスに必要なデータ フィールドを含む構造体を作成し、classその構造体からオブジェクトを作成することを示す関数を呼び出します。既存のオブジェクトの子を作成するには、親クラスのオブジェクトを作成し、そのオブジェクトをクラス関数の 3 番目の引数として指定します。

これは例で示すのが最も簡単です。プログラマーが FIR フィルター、つまり分子多項式で分母が 1 のフィルターを必要としているとします。従来の Octave プログラミングでは、これは次のように実行されます。

x = [some data vector];

n = [some coefficient vector];

y = filter (n, 1, x);
同等の動作はクラスとして実装できます@FIRfilter。このクラスのコンストラクタはファイルです。FIRフィルター.mクラスディレクトリ内@FIRフィルター。

## -*- texinfo -*-
## @deftypefn  {} {} FIRfilter ()
## @deftypefnx {} {} FIRfilter (@var{p})
## Create a FIR filter with polynomial @var{p} as coefficient vector.
## @end deftypefn
function f = FIRfilter (p)
 if (nargin == 0)
   p = @polynomial ([1]);
 elseif (! isa (p, "polynomial"))
   error ("@FIRfilter: P must be a polynomial object");
 endif
 f.polynomial = [];
 f = class (f, "FIRfilter", p);
endfunction

以前と同様に、先頭のコメントはクラス コンストラクタのドキュメントを提供します。このコンストラクタは、多項式クラス コンストラクタと非常に似ていますが、多項式オブジェクトが関数の 3 番目の引数として渡されclass、クラスが多項式クラスから派生されることを Octave に伝える点が異なりますFIRfilter。FIR フィルタ クラス自体にはデータ フィールドはありませんが、class 関数に構造体を提供する必要があります。コンストラクタがオブジェクト構造体に多項式@polynomialという名前の要素を追加することを考えると、構造体はダミー フィールド多項式で初期化され、後で上書きされます。 @FIRfilter

サンプル コードでは、引数が指定されていない場合が常に考慮されていることに注意してください。これは、継承構造を決定するために、保存されたファイルからオブジェクトをロードするときに、Octave が引数なしでコンストラクタを呼び出すため重要です。

クラスは複数のクラスの子になることができ (クラスを参照)、継承はネストされることがあります。メモリやその他の物理的な問題を除き、親の数やネストのレベルに制限はありません。

クラスではFIRfilter、オブジェクトの表示についてより詳細な制御が求められます。そのため、メソッドdisplayではなくメソッドdisp がオーバーロードされます (クラスメソッドを参照)。簡単な例は次のようになります。

function display (f)
 printf ("%s.polynomial", inputname (1));
 disp (f.polynomial);
endfunction

FIRfilterの display メソッドは、実際にフィルタ係数を表示するために、クラスdisp の メソッドに依存していることに注意してください。さらに、メソッドでは、表示する変数名とその後に値を出力する Octave の残りの部分と一貫性を保つために、 メソッドを 行で開始することが理にかなっていること に注意してください。一般に、関数をオーバーロードすることは推奨されません 。 polynomialdisplayprintf ("%s =", inputname (1))display

: display (obj)
オブジェクトobjの内容をその名前の先頭に付けて表示します。

Octave インタープリタは、displayクラスを画面に表示する必要があるときはいつでも関数を呼び出します。通常、これは出力を抑制するためにセミコロンで終わらないステートメントになります。例:

myclass (...)

または:

myobj = myclass (...)

一般に、ユーザー定義クラスは、dispデフォルトの出力を回避するためにメソッドをオーバーロードする必要があります。

myobj = myclass (...)
 ⇒ myobj =
 <class myclass>

代わりにメソッドをオーバーロードする場合はdisplay、オブジェクトの名前を適切に表示するように注意する必要があります。これは、 inputname関数を使用して実行できます。

See also: disp, class, subsref, subsasgn.

コンストラクタと表示メソッドが存在すると、クラスのインスタンスを作成できます。また、クラスの種類をチェックし、基礎となる構造を調べることもできます。

octave:1> f = FIRfilter (polynomial ([1 1 1]/3))
 f.polynomial = 0.33333 + 0.33333 * X + 0.33333 * X ^ 2
octave:2> class (f)
ans = FIRfilter
octave:3> isa (f, "FIRfilter")
ans =  1
octave:4> isa (f, "polynomial")
ans =  1
octave:5> struct (f)
ans =
 scalar structure containing the fields:
polynomial = 0.33333 + 0.33333 * X + 0.33333 * X ^ 2

このクラスを使えるようにするために残っているのは、データを処理するメソッドだけです。しかし、その前に、クラスに格納されているデータを変更する方法も用意しておくことが望ましいです。基盤となる構造体のフィールドはデフォルトでプライベートなので、フィールドにアクセスするためのメカニズムを提供する必要があります。このsubsrefメソッドは、両方のタスクに使用できます。

function r = subsref (f, x)
 switch (x.type)
   case "()"
     n = f.polynomial;
     r = filter (n.poly, 1, x.subs{1});
   case "."
     fld = x.subs;
     if (! strcmp (fld, "polynomial"))
       error ('@FIRfilter/subsref: invalid property "%s"', fld);
     endif
     r = f.polynomial;
   otherwise
     error ("@FIRfilter/subsref: invalid subscript type for FIR filter");
 endswitch
endfunction

この"()"場合、コンストラクターに提供された多項式を使用してデータをフィルター処理できます。

octave:2> f = FIRfilter (polynomial ([1 1 1]/3));
octave:3> x = ones (5,1);
octave:4> y = f(x)
y =
  0.33333
  0.66667
  1.00000
  1.00000
  1.00000

この"."場合、多項式体の内容を表示できます。

octave:1> f = FIRfilter (polynomial ([1 1 1]/3));
octave:2> f.polynomial
ans = 0.33333 + 0.33333 * X + 0.33333 * X ^ 2

オブジェクトの内容を変更するにはsubsasgnメソッドが必要です。たとえば、次のコードは多項式フィールドを公開書き込み可能にします。

function fout = subsasgn (f, index, val)
 switch (index.type)
   case "."
     fld = index.subs;
     if (! strcmp (fld, "polynomial"))
       error ('@FIRfilter/subsasgn: invalid property "%s"', fld);
     endif
     fout = f;
     fout.polynomial = val;
   otherwise
     error ("@FIRfilter/subsasgn: Invalid index type")
 endswitch
endfunction

となることによって

octave:1> f = FIRfilter ();
octave:2> f.polynomial = polynomial ([1 2 3])
f.polynomial = 1 + 2 * X + 3 * X ^ 2

FIRfilter クラスを多項式クラスの子として定義すると 、多項式オブジェクトが使用できる場所であればどこでも FIRfilter オブジェクトを使用できることになります。これはフィルタの通常の使用法ではありません。継承ではなく集約を使用する方が賢明な設計アプローチかもしれません。この場合、多項式はクラス構造内の単なるフィールドです。集約の場合のクラス コンストラクターは次のようになります。

## -*- texinfo -*-
## @deftypefn  {} {} FIRfilter ()
## @deftypefnx {} {} FIRfilter (@var{p})
## Create a FIR filter with polynomial @var{p} as coefficient vector.
## @end deftypefn
function f = FIRfilter (p)
 if (nargin == 0)
   f.polynomial = @polynomial ([1]);
 else
   if (! isa (p, "polynomial"))
     error ("@FIRfilter: P must be a polynomial object");
   endif
   f.polynomial = p;
 endif
 f = class (f, "FIRfilter");
endfunction

この例では、コンストラクターのみを変更する必要があり、他のすべてのクラス メソッドは同じままです。