34.5继承和聚合

Octave通过使用继承和聚合来支持使用类来构建新类。

类继承是从Octave使用提供的class类构造函数中的函数。与多项式类的情况一样,Octaveprogrammer将创建一个包含该类所需数据字段的结构体,然后调用class函数来指示要从结构体中创建的对象。创建现有对象的子对象是通过创建父类的对象并将该对象提供为类函数的第三个参数来完成的。

这很容易通过例子来证明。假设程序员需要FIR滤波器,即分子多项式但分母为1的滤波器。在传统的Octave编程中,这将按如下方式执行。

>> x = [some data vector];
>> n = [some coefficient vector];
>> y = filter (n, 1, x);

等效行为可以实现为类@FIRfilter。此类的构造函数是文件FIRfilter.m在类目录中@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)
    p = @polynomial ([1]);
  elseif (! isa (p, "polynomial"))
    error ("@FIRfilter: P must be a polynomial object");
  endif

  f.polynomial = [];
  f = class (f, "FIRfilter", p);

endfunction

和前面一样,前导注释提供了类构造函数的文档。此构造函数与多项式类构造函数非常相似,只是将多项式对象作为第三个参数传递给class函数,告诉OctaveFIRfilter类将从多项式类导出。FIR滤波器类本身没有任何数据字段,但它必须向class作用考虑到@polynomial构造函数将添加一个名为的元素polynomial到对象结构体@FIRfilter使用伪字段对结构体进行just初始化polynomial其稍后将被覆盖。

请注意,示例代码总是提供不提供参数的情况。这一点很重要,因为Octave在从保存的文件中加载对象以确定继承结构体时,将调用不带参数的构造函数。

一个类可以是多个类的子类(详见),并且可以嵌套继承。除了内存或其他物理问题外,父级对象的数量或嵌套级别没有限制。

对于FIRfilter类,则需要对对象显示进行更多控制。因此display方法而不是disp方法重载(详见类方法). 一个简单的例子可能是

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

请注意FIRfilter的显示方法依赖于disp的方法polynomial类以实际显示滤波器系数。此外,请注意,在display方法它使方法从线开始printf ("%s =", inputname (1))以与Octave的设置一致,Octave打印要显示的变量名和值。一般情况下,不建议重载display作用

 
: display (obj)

显示对象的内容obj以其名称为前缀。

Octave解释器调用display只要需要就可以在屏幕上显示类。通常,这将是一个不以分号结尾以抑制输出的语句。例如

myclass (...)

myobj = myclass (...)

通常,用户定义的类应该重载disp方法使默认输出无效:

myobj = myclass (...)
  ⇒ myobj =

  <class myclass>

当重载时display方法,必须注意正确显示对象的名称。这可以通过使用inputname作用

详见: 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

这个"()"case允许我们使用提供给构造函数的多项式来过滤数据。

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

这个"."case允许我们查看多项式字段的内容。

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

对于这个例子,只有构造函数需要更改,所有其他类方法保持不变。


版权所有 © 2024-2025 Octave中文网

ICP备案/许可证号:黑ICP备2024030411号-2