2011-10-07 59 views
3

我有2类A和B,B是从A继承,A是从NSObject.Class甲继承具有如下功能: - (无效)INIT:目标C init方法和继承

- (void)init { 
if (self = [super init]) { 

NSLog(@"A");  

} 
return self; 
} 

B具有:

- (id)init { 
if (self = [super init]) { 

NSLog(@"B");  

} 
return self; 
} 

编译后,我在我的控制台“A”和“B”的,尽管在B“如果(自= [超级初始化])”不可能是真实的情况,导致其超类的init方法返回void.Any想法?

P.S.我知道init方法必须返回id,我感兴趣的是为什么这个工作,而不应该。

回答

5

听Chuck。他很聪明:)

我会尝试添加更多的细节。想想这个

的方法之一是“如果两人都宣布-(id)init如何将一个返回其值设置为B”?

它是这样的。 return self声明将把指针指向A,并将其放在约定的位置。该位置将在ABI中定义。在OSX/x86-64机器上,它是RAX寄存器(IIRC)。所以return self真的说“把自己的指针写入RAX”。

然后当B重新获得控制,它知道返回值是RAX,并且可以使用它是什么样子。请注意,您并未从A的实施中删除return self声明,因此自我可能仍然写入RA中,B发现并使用它。或者也许RAX仍然有NSObject init实现的指针。你必须反汇编才能确定。

现在,让我们说你没有保持return self在A的实施。现在,RA中有一些随机垃圾,B将尝试使用它,像是指向A的指针。这是Chuck提到的未定义行为的来源。如果幸运的话,它只会崩溃。

我猜你的代码上面给出了一些编译器错误/警告,你必须压制?

+0

是,警告“回归与空函数” –

+3

IIRC,一些编译器会扔掉返回值的void函数,即使你明确地写出来。它看来,苹果的不对,但它没有什么依赖。这真的是*未定义的行为发挥作用。 – Chuck

5

您正在通过分配void函数调用的结果来调用未定义的行为。未定义的行为意味着几乎可以发生任何事情。这属于“任何东西”的标题,所以它可能发生。至于为什么编译器没有注意到你的错误:你可能忽略了在你的头文件中声明重写,所以它假定你的方法和它可以找到的最近的声明NSObject一样具有相同的签名。