问题描述
在MATLAB中将类属性验证与抽象属性结合使用时,出现(对我而言)意外的行为。这是一个涉及三个类的简短示例:
classdef TestClass
properties (Abstract)
aprop (1,1) TestClassB
end
end
classdef TestClassB
methods
function obj = TestClassB(a)
disp(a);
end
end
end
classdef TestClassC < TestClass
properties
aprop
end
end
然后,当尝试实例化TestClassC
对象时,出现以下错误:
>> TestClassC()
Error defining property 'aprop' of class 'TestClass'. Unable to construct default
object of class TestClassB.
很明显,MATLAB试图实例化aprop
中的抽象属性TestClass
,然后由于aprop
的类定义{{中缺少有效的零参数构造函数而失败。 1}}。我意识到零参数构造函数问题在理论上是可以解决的(尽管只有在您有权修改TestClassB的情况下),但是MATLAB完全实例化抽象属性的事实似乎很奇怪。维基百科有关抽象类型的文章的第一行从字面上指出:
...抽象类型是不能直接实例化的名词性类型系统中的类型...
也许这是MATLAB作为弱类型语言实现属性验证的唯一方法,但这是不幸的结果。
另一方面,如果TestClassB
具有有效的零参数构造函数,但被定义为抽象的,则最终会陷入相同的陷阱,但错误略有不同:
TestClassB
这种行为是否有充分的理由?
编辑:
其他测试班观察结果
- 删除
>> TestClassC() Error defining property 'aprop' of class 'TestClass'. Class TestClassB is abstract. Specify a default value for property aprop.
中的大小验证可消除该错误。显然,在没有有效的零参数构造函数的情况下,MATLAB初始化对象的空数组没有问题。注意:仅当TestClass
是不是抽象时,此功能才起作用。 - 如果
TestClassB
是抽象的,并且TestClassB
在属性块中用TestClassC
的具体子类初始化aprop
,则没有错误(假设具体子类具有有效的零参数构造函数)。注意:如果TestClassB
是在aprop
的构造函数中初始化的,则 not 为true。
激励例子
上面的UML图是将继承与组合相结合的典型示例。 TestClassC
和GenericCar
是抽象类。 GenericEngine
包含一个GenericCar
,但是GenericEngine
将其引擎指定为具体的Racecar
(“ isa” V8
)。不幸的是,这不能使用MATLAB中的属性验证来构造,因为MATLAB不允许您重新定义抽象属性的类,即使它是原始定义的子类也是如此。
假设您接受不能将GenericEngine
中的engine
定义为Racecar
。即使这样,如果您没有在V8
的属性块中为engine
提供一个初始值,则MATLAB会在创建Racecar对象时抛出错误,因为它将尝试使用抽象类型Racecar
初始化engine
。即使GenericEngine
的构造函数将引擎初始化为Racecar
对象也是如此。 这突出了属性验证和对象实例化之间的奇特联系。
解决方法
似乎应该回答两个问题:
1-“很明显,MATLAB试图实例化aprop
中的抽象属性TestClass
。那么为什么MATLAB试图实例化抽象属性?”
根据documentation(我强调):
您可以定义抽象属性的属性验证。验证适用于实现该属性的所有子类。
MATLAB正在尝试实例化aprop
中的属性TestClassC
,该属性是TestClass
的 concrete 子类。但是它使用与TestClass
中使用的相同验证规则。 aprop
的{{1}}属性不是抽象的。
2-“如果TestClassC
...被定义为抽象的,您最终将陷入同一陷阱...”
抽象类 —一个无法实例化的类,但它定义了子类使用的类组件。
TestClassB
使用与TestClassC
中相同的验证规则。它尝试实例化其属于TestClass
类的aprop
成员,但是TestClassB
是抽象的并且无法实例化。