微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

是否可以从旧式类派生出 classdef 类?

如何解决是否可以从旧式类派生出 classdef 类?

是否可以从旧式类派生出 classdef 类?

在 Octave 4.0 中,ss 类是在旧样式中定义的,带有 @ss 目录。 我想在位于 __freqresp__文件 myss.m 中使用自定义 path 方法派生一个类,并具有以下内容

classdef myss < ss
methods
function x = solve_svd(A,b)
  [U,S,V] = svd(A);
  si = 1.0 ./ diag(S);
  si(~isfinite(si)) = 0;
  x = V' * diag(si) * U'*b;
endfunction

function H = __freqresp__ (sys,w,cellflag = false)

  if (sys.scaled == false)
    sys = prescale (sys);
  endif

  [a,b,c,d,e,tsam] = dssdata (sys);

  if (isct (sys))  # continuous system
    s = i * w;
  else             # discrete system
    s = exp (i * w * abs (tsam));
  endif

  H = arrayfun (@(x) c*solve_svd(s*E-A,b) + d,s,"uniformoutput",false);

  if (! cellflag)
    H = cat (3,H{:});
  endif

endfunction
endmethods
endclassdef

遗憾的是,即使加载了 ss 包,Octave 也会抱怨未知类 control

解决方法

(我在这里从 MATLAB 的角度回答,因为这是我最了解的,但 Octave 在这里具有完全相同的行为,因此它同样适用于 Octave。)

@ 样式类的问题在于,MATLAB 在创建类的对象之前不知道它们的属性。因此,要使用旧式类作为基类,MATLAB 必须构造一个基对象来了解类的外观,但是使用错误的输入调用构造函数可能会导致错误消息。或者构造函数可以完成数小时的工作。仅仅为了了解对象的外观而构建对象是不可行的。

我认为这是引入 classdef 样式类的核心原因。还有其他改进,但没有一个比这更重要。在 @ 风格的类中,继承是在对象创建时确定的,必须先手动创建基类的对象,然后将这些对象合并到正在创建的派生对象中。


以下是 @ 样式类行为的一个有趣示例,该示例使其无法用作 classdef 样式类中的基类:

@foo/foo.m:

function obj = foo(x)
if x
   obj = class(struct('a','a'),'foo');
else
   obj = class(struct('b','b'),'foo');
end

现在我们在 MATLAB 中输入:

>> a=foo(0)
a = 
    foo object: 1-by-1
>> b=foo(1)
Error using class
[...]
>> clear classes
>> b=foo(1)
b = 
    foo object: 1-by-1
>> a=foo(0)
Error using class
[...]

foo 的变化取决于类的第一个对象的创建方式。一旦我们以一种方式创建了一个对象,另一种方式就变得非法了。


OP 原始问题的解决方案:

在 Octave 4.0 中,ss 类是在旧样式中定义的,带有 @ss 目录。我想用自定义的 __freqresp__ 方法 [...] 派生一个类。

与其派生一个带有自定义方法的新类,不如考虑覆盖现有方法。只需创建一个目录@ss,并在其中放置一个文件__freqresp__.m。确保您的 @ss 目录位于 Octave 路径上的目录中,该目录位于原始类所在的工具箱目录之前

我假设原始 __freqresp__.m 是一个实际方法,而不是类的 private 子目录中的函数。如果是这样,则它不是一种方法并且不能被覆盖(请参阅 Octave 手册中的 Function Precedence)。

请注意,您可以覆盖任何类型的重载函数,甚至是内置类型。例如,您可以创建一个函数 @double/length.m 以在使用普通(双)矩阵调用时覆盖 length 函数。

,

将我在评论中的回答扩展为一个例子。

就像我在评论中所说的,我认为混合 classdef 和经典的面向对象风格是不可能的。因此,我会使用“经典”的 OO 风格来代替执行“重载”,这无论如何都相当简单。

然而,与 matlab/octave 中的许多其他语法一样,经典风格使用文件系统语义来定义各自的命名空间,并且您有额外的要求,即您希望在单个文件中编写所有这些功能。

然后想到的显而易见的解决方法是在文件系统上“即时”创建必要的文件/命名空间,然后稍后在主代码中适当地加载该类定义。显然,这并不是真正推荐的处理类(新旧)的方法,但是,如果您确实必须从单个文件中工作,那么它不是也很难做到。

这是一个(独立的)示例来演示这一点(即将代码复制到脚本中,然后以八度音程运行脚本):

% Create class structure in a temporary directory
  ClassPath     = tempname();
  ClassDir      = fullfile( ClassPath,'@myss' );
  Constructor_m = fullfile( ClassDir,'myss.m' );
  Freqresp_m    = fullfile( ClassDir,'__freqresp__.m' );
  mkdir( ClassPath )
  mkdir( ClassDir )

% Define constructor
  f = fopen( Constructor_m,'w' );
  fdisp( f,'   function Out = myss( sys )           ' );
  fdisp( f,'     Out = struct();                    ' );
  fdisp( f,'     Out = class( Out,"myss",sys );   ' );
  fdisp( f,'   endfunction                          ' );
  fclose(f);

% Define overriding __freqresp__ method
  f = fopen( Freqresp_m,'   function H = __freqresp__ (sys,w,cellflag = false)                           ' );
  fdisp( f,'                                                                                  ' );
  fdisp( f,'       if get( sys,"scaled" ) == false                                           ' );
  fdisp( f,'         sys = myss( prescale (sys) );                                            ' );
  fdisp( f,'       endif                                                                      ' );
  fdisp( f,'       [a,b,c,d,e,tsam] = dssdata (sys);                                     ' );
  fdisp( f,'       if (isct (sys))  # continuous system                                       ' );
  fdisp( f,'         s = i * w;                                                               ' );
  fdisp( f,'       else             # discrete system                                         ' );
  fdisp( f,'         s = exp (i * w * abs (tsam));                                            ' );
  fdisp( f,'       H = arrayfun (@(x) c*solve_svd(s*e-a,b) + d,s,"uniformoutput",false);   ' );
  fdisp( f,'       if (! cellflag)                                                            ' );
  fdisp( f,'         H = cat (3,H{:});                                                       ' );
  fdisp( f,'   endfunction                                                                    ' );
  fclose(f);

% Load class definition
  addpath( ClassPath );

% Note: this does not need to be a class member (technically it wasn't one before either).
  function x = solve_svd(A,b)
    [U,S,V] = svd(A);
    si = 1.0 ./ diag(S);
    si(~isfinite(si)) = 0;
    x = V' * diag(si) * U'*b;
  endfunction

% Main code using derived 'myss' class.
  pkg load control
  a = [1,2,3; 4,5,6; 7,8,9]; 
  b = [10;11;12];
  stname = {'V','A','kJ' };
  sys = ss( a,'stname',stname );
  mysys = myss( sys );
  disp( 'The freqresp using the overriden __freqresp__ method is:' );
  disp( __freqresp__( mysys,5 ) );
,

没有。新式 classdef ("MCOS") 类与旧式类是一种不同的机制,它们不能通过继承来组合。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。