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
方法它使方法从线开始
以与Octave的设置一致,Octave打印要显示的变量名和值。一般情况下,不建议重载printf ("%s =", inputname (1))
display
作用
一旦构造函数和显示方法存在,就可以创建类的实例。也可以检查类类型并检查底层结构体。
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