Mar*_*arc 9 oop polymorphism matlab matlab-class
我有两个新式的MATLAB类 - B&C,它们都是抽象父类的具体子类A. A是hgsetset(句柄类)的子类.我想将它们放在MATLAB中的数组中,并将它们视为As.它们大致定义为:
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
Run Code Online (Sandbox Code Playgroud)
但是,如果我这样做:
arr = [b c]; % where b & c are objects of type B & C respectively.
arr(1).foo;
arr(2).foo;
Run Code Online (Sandbox Code Playgroud)
MATLAB将告诉我两者都是类型B,如果我从A两个实现(foo)调用抽象方法,它实际上执行两个副本b.
但是,如果我颠倒顺序:
arr = [c b];
Run Code Online (Sandbox Code Playgroud)
它告诉我两者都是类型C,如果我尝试在两者上执行foo,它执行,基本上是两个副本c.
任何想法如何以多态方式使用子类?
我知道我可以把它们放在一个单元阵列中,并获得我需要的90%.但这有点像kludge.
Tho*_*son 17
您现在可以通过继承matlab.mixin.Heterogeneous在R2011a中完成此操作.例如,在您的代码中,抽象类将是:
classdef A < matlab.mixin.Heterogeneous
methods
function foo(this)
disp('In abstract parent');
this.fooWorker;
end
end
methods(Abstract, Access=protected)
fooWorker(this);
end
end
Run Code Online (Sandbox Code Playgroud)
子类看起来像:
classdef B < A
methods(Access=protected)
function fooWorker(this)
disp('In B');
end
end
end
Run Code Online (Sandbox Code Playgroud)
类似于'C'类.然后,这给出了MATLAB的以下输出:
>> b = B;
>> c = C;
>> arr = [b, c];
>> arr(1).foo
In abstract parent
In B
>> arr(2).foo
In abstract parent
In C
>>
Run Code Online (Sandbox Code Playgroud)
不幸的是,MATLAB中数组的所有元素必须属于同一类型.当您连接不同的类时,MATLAB将尝试将它们全部转换为同一个类.
如果您已将某个类定义为低于或高于另一个类(使用InferiorClasses属性或INFERIORTO/SUPERIORTO函数),则会调用更高级类的方法.如果尚未指定类之间的关系,则两个对象具有相同的优先级,MATLAB调用最左侧的对象方法.这可能是为什么要arr = [b c];创建一个B类数组并arr = [c b];创建一个C类数组的原因.
如果要foo在对象上执行为类B定义的方法b,并且还要在对象上执行foo为类C定义的方法c,则可能必须使用单元数组和函数CELLFUN.如果foo没有返回值,您可以执行以下操作:
arr = {b,c};
cellfun(@foo,arr); % Invoke foo on each element of the cell array
Run Code Online (Sandbox Code Playgroud)
为了好玩,我想出了一个技术上有效的潜在解决方案,但有一些局限性.为了说明这个想法,我整理了一些类似于你在问题中列出的样本类.这是抽象的超类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
Run Code Online (Sandbox Code Playgroud)
这里是子类的一个例子classB(classC在任何地方B被替换为完全相同,C反之亦然):
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
Run Code Online (Sandbox Code Playgroud)
构造函数用于classB和classC设计为使得两个类可以相互转换.该属性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!
Run Code Online (Sandbox Code Playgroud)
一个关键性的限制(除了作为一个小难看)是其中的情况下classB,并classC各自具有另一个没有的特性.在这种情况下,转换到另一个类然后转换回来可能会导致这些属性丢失(即重置为其默认值).但是,如果一个类是另一个类的子类,那么它具有所有相同的属性和thensome,那么就有一个解决方案.您可以将子类设置为优于超类(参见上面的讨论),这样两个类的连接对象将始终导致超类对象转换为子类.当在"多态"方法(foo如上所述)内转换回来时,不会丢失任何对象数据.
我不知道解决方案是多么可行,但也许它至少会给你一些有趣的想法.;)