子类中的窄属性类型

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类型)(代码

java中的强制类型转换