26

我正在使用一个定义和使用“ClassA”的框架,它是 NSObject 的子类。我想添加一些变量和功能,所以我自然地创建了“ClassB”,它是“ClassA”的子类

现在我的问题是这个。此框架中的许多方法返回我想转换为我的子类的“ClassA”实例。

例如采取这种方法:

- (ClassA *)doSomethingCool:(int)howCool

现在在我的代码中我试试这个:

ClassB * objB;
objB = (ClassB *)doSomethingCool(10); 

NSLog(@"objB className = %@", [objB className]);

这运行得很好。没有编译或运行时错误或任何东西。但对我来说真正奇怪的是输出:

>> "objB className = ClassA"

选角显然失败了。不知道此时发生了什么...... objB 被键入为“ClassB”,但它的 className 是“ClassA”,它不会响应任何“ClassB”方法。

不知道这怎么可能......有人知道我在这里做错了什么吗?

我发现了一个与我在这里问的完全相反的类似帖子

4

5 回答 5

26

在 Objective-C 中强制转换对象变量通常是一个错误(在少数情况下它是正确的,但从来没有这样的事情)。请注意,您不是在转换对象——您是在转换指向对象的指针。然后你有一个 type 的指针ClassB*,但它仍然指向 ClassA 的同一个实例。指向的东西根本没有改变。

如果您真的想将 ClassA 的实例转换为 ClassB,则需要编写一个 ClassB 构造函数方法,该方法可以从 ClassA 创建一个 ClassB 实例。如果您确实需要添加实例变量,这可能是您的最佳选择。

不过,正如 Jason 所说,首先尝试一个类别通常是个好主意。

于 2009-08-06T02:26:43.740 回答
19

您不能只将超类转换为其子类。它实际上并没有实现您添加的任何变量/属性或方法。一旦您尝试使用您在子类上定义的方法向它发送消息,您将获得运行时异常并且您的应用程序将退出。您只能安全地朝一个方向投掷:从更具体到更一般。即,您可以安全地将我们的 ClassB 转换为 ClassA,只使用 ClassA 的方法和属性,反之则不行。

可以这样想:你有一个 Car(父类)和一个 FourDoorSedan(子类)。每辆车都有一个发动机和两扇门。现在,假设你从某个地方买了一辆车,这就是你所知道的一切。你告诉接线员,那辆车是四门轿车,但事实证明它不是。因此,当操作员执行以下操作时:openBackPassengerDoor,会发生什么?只有两扇门!!这里也一样。

如果您只想向 ClassA 添加一些功能,请查看 Objective-C 类别,它们可能是您想要的,并且不需要强制转换。但是,请仔细阅读文档,因为它们并非没有警告。

于 2009-08-06T01:31:50.003 回答
5

如果您只想为现有对象添加方法,则子类化不是正确的方法。您可以使用名为category的语言功能向现有类(及其实例)添加方法。

例子:

//"ClassA+doSomethingCool.h"
@interface ClassA (doSomethingCool)
- (ClassA *)doSomethingCool:(int)howCool;
@end


//"ClassA+doSomethingCool.m"
@implementation ClassA (doSomethingCool)
- (ClassA *)doSomethingCool:(int)howCool
{

}
@end
于 2009-08-06T09:51:26.223 回答
2

铸造不会从一种类型的对象转换为另一种类型的对象。您不能强制某些库更改对象类型并创建另一种类型的对象,除非它使用某种工厂模式。

于 2010-10-30T00:38:09.073 回答
0

当您在返回的对象上调用您的子类方法之一时会发生什么?

ClassB * objB;
objB = (ClassB *)doSomethingCool(10);
[objB subClassMethod];

Obj-C 是非常自由的,并且会丢失类型,您甚至不需要事先知道类型,例如。您可以将所有 ClassB 引用更改为 id。我知道知道你有预期的类型会更安全,但如果你的代码是正确的,那就没关系了。

于 2009-08-06T02:20:34.717 回答