1

我有一种感觉,这将是一个非常快速的答案。我正在上 Paul Hegarty 的斯坦福 iOS 开发课程,他提到了选角。我对 Java 有一些经验,但没有遇到过强制转换,所以我想这也可能是关于强制转换的一般问题。我似乎无法在网上找到简洁的解释。他给出的代码是:

@interface Vehicle
- (void)move;
@end
@interface Ship : Vehicle
- (void)shoot;
@end

Ship *s = [[Ship alloc] init];
[s shoot];
[s move];

Vehicle *v = s;
[v shoot];

id obj = ...;
[obj shoot];
[obj someMethodNameThatNoObjectAnywhereRespondsTo];

// I understand up to this far, but it's the casting I'm having difficulty with

NSString *(hello) = @"hello";
[hello shoot];
Ship *helloShip = (Ship *)hello; 
[helloShip shoot];

所以在第一行,他创建了一个指向 NSString 的指针,叫做 hello。在第二行中,他调用了 hello 的 shoot 方法,它是一个 NSString,但该方法不存在,因此无法正常工作。在第三行中,他创建了一个指向名为 helloShip 的 Ship 对象的指针,并将其设置为等于什么?将 NSString 指针转换(转换?)为船舶指针?如果是这样,为什么呼叫射击会失败?

4

3 回答 3

4

强制转换不会将对象转换为不同类型的类。它只是使编译器将某个对象视为那种类型(Hermanns 的示例就说明了这一点)。

在你的例子hello中是NSString *类型。将其转换为Ship *并调用其shoot方法将编译 - 并崩溃。

即使在铸造之后hello仍然是一个NSString *.

这并不意味着铸造是无用的。以数组或示例为例。[anArray objectAtIndex:x]除非您将结果转换为(正确的)类型,否则编译器不知道会返回什么。

另一个例子是:

-(void)objectTapped:(id)sender
{
    if ([sender isKindOfClass:[UIButton class]])
    {
      UIButton *aButton = (UIButton *)sender;
      //use all UIButton methods and properties
    }
    else if ([sender isKindOfClass:[UILabel class]])
    {
      UILabel *aLabel = (UILabel *)sender;
      //use all UILabel methods and properties
    }
}

因此,铸造可能非常有用,但如果使用不当也会很危险。

于 2013-11-10T14:20:33.333 回答
4

转换实际上并没有改变对象的类,也不会重新格式化被转换对象的任何内容。

外壳只告诉编译器“闭嘴!我是负责的程序员,我知道我在做什么。吃掉它,编译它,让它运行。”

就是这样。不少于,也不少于。通过这样做,您有责任确保对象能够很好地响应发送的消息。

但是,使用 ARC,您的样本甚至不会出现。您不能简单地发送shoot到类型的对象Vehicle,因为Vehicle该类及其对象不响应shoot

如果没有 ARC,您可以向每个对象发送任何消息,并希望对象在运行时响应它。到目前为止,您的示例代码将运行,因为分配(和强制转换)到的对象v仍然是Ship确实响应的类型shoot

NSStringshoot无论您多久将其投射到您想要的任何东西,都永远不会回应。(当然,除非您NSString使用实现 的类别进行扩展shoot。但这是一个不同的主题。)

于 2013-11-10T14:32:39.923 回答
0

不,它不起作用,你正在尝试类似下面的东西

int age=(int)@"My age is 60";

那是行不通的。

它必须是那种类型的类型,在你的情况下,你试图对两者进行类型转换NSString *Ship含义是不同的。所以它不会工作。

于 2013-11-10T14:23:27.767 回答