子类中的窄属性类型
Posted
技术标签:
【中文标题】子类中的窄属性类型【英文标题】:Narrow type of property in subclass 【发布时间】:2012-05-23 00:04:08 【问题描述】:今天我遇到了一个我没想到 Objective-C 编译器会允许的奇怪行为。
在 UITableViewCell 中,有一个 UIImageView 类型的名为 imageView 的属性。我继承了 UITableViewCell 并覆盖了 imageView,除了我将它设为 AWImageView 类型,其中 AWImageView 是 UIImageView 的子类。我以为它不会编译,但确实如此。一切正常。我对这种行为感到非常震惊。
是否正式允许缩小子类中的属性类型?或者这是 Objective-C 编译器中的一个错误使它工作?
【问题讨论】:
【参考方案1】:您对被允许这样做的怀疑是有根据的,但在这种特殊情况下,您还可以...
在对重写的严格子类型解释中,重写方法可以接受更通用类型的参数并返回更具体类型的值。
例如,使用 Objective-C,给定:
@interface A : NSObject ...
@interface B : A ...
@interface C : B ...
和B中的方法M:
- (B *) M:(B *)arg ...
然后在严格的子类型下的 C 类中,这可以在 C 类中使用:
- (C *) M:(A *)arg ...
这是安全的,因为如果你有一个明显 B 对象的引用:
B *bObj = ...;
然后调用方法M:
B *anotherBObj = [bObj M:[B new]];
那么无论bObj
实际上是B还是C,调用的类型都是正确的——如果它是一个C对象,那么参数是B就可以了,因为它也是A,结果是C就可以了它也是一个B。
这将我们带到,不完全,您的财产;在 Objective-C 中,属性只是两种方法的简写:
@property B *myBvalue;
是以下的简写:
- (void) setMyBvalue:(B *)value;
- (B *) myBvalue;
如果该属性在 B 中声明,并且您在 C 类中使用 C 值属性覆盖它:
@property C *myBvalue;
你得到:
- (void) setMyBvalue:(C *)value;
- (C *) myBvalue;
并且setMyBvalue:
方法违反了严格的子类型化规则 - 将 C 实例强制转换为 B 实例,并且类型化规则说您可以传递 B,该方法需要一个 C,然后就会出现混乱。
但是在您的情况下,您要覆盖的属性是 readonly
,因此没有设置器,也没有危险。
【讨论】:
【参考方案2】:如果 AWImageView 从 UIImageView 派生(子类),它是一个 UIImageView,所以对于编译器来说都是一样的。
from the docs:
图 1-1 […] 这只是说 Square 类型的对象不仅是正方形,它还是矩形、形状、图形和 NSObject 类型的对象。
【讨论】:
你知道有什么文件可以支持吗?我很确定 Objective-C 之前不允许这样做。 -(id)init 返回 id 因为它不允许子类覆盖方法并返回更窄的类型。 这在任何支持继承的基于类的面向对象语言中都是非常正常的行为。子类可以被视为父类。而你在初始化时弄错了:它指定了 id,因此任何子类都可以返回自己的对象(或 [参见类集群] 另一个类,其行为类似)。 文档中的好引述,但只是想指出您引述中的图像是死链接。以上是关于子类中的窄属性类型的主要内容,如果未能解决你的问题,请参考以下文章
强制 ASP NET Core 控制器不序列化子类返回类型中的属性
实现一个名为Person的类和它的子类Employee,Employee有两个子类Faculty 和Staff。
实现一个名为Person的类和它的子类Employee,Employee有两个子类Faculty 和Staff。
23.实现一个名为Person的类和它的子类Employee,Employee有两个子类Faculty 和Staff。 具体要求如下: Person类中的属性有:姓名name(String类型)
23.实现一个名为Person的类和它的子类Employee,Employee有两个子类Faculty 和Staff。 具体要求如下: Person类中的属性有:姓名name(String类型)(代码