为什么gcc用`self = [super initDesignatedInit];'警告不兼容的struct赋值?在派生类中调用?

时间:2010-03-12 14:52:33

标签: objective-c gcc warnings

我在Objective-C中设置了以下基类/派生类:

@interface ASCIICodeBase : NSObject {
 @protected
  char code_[4];
}
- (Base *)initWithASCIICode:(const char *)code;
@end

@implementation ASCIICodeBase
- (ASCIICodeBase *)initWithCode:(const char *)code len:(size_t)len {
  if (len == 0 || len > 3) {
    return nil;
  }
  if (self = [super init]) {
    memset(code_, 0, 4);
    strncpy(code_, code, 3);
  }
  return self;
}
@end

@interface CountryCode : ASCIICodeBase
- (CountryCode *)initWithCode:(const char *)code;
@end
@implementation CountryCode
- (CountryCode *)initWithCode:(const char *)code {
  size_t len = strlen(code);
  if (len != 2) {
    return nil;
  }
  self = [super initWithCode:code len:len]; // here
  return self;
}
@end

在标有“此处”的行上,我收到以下gcc警告:

warning: incompatible Objective-C types assigning 'struct ASCIICodeBase *', expected 'struct CurrencyCode *'

此代码有问题或我应该ASCIICodeBase返回id吗?或者也许在“这里”一行使用演员?

2 个答案:

答案 0 :(得分:4)

您应该将返回值强制转换为(CountryCode *)。该方法返回类型ASCIICodeBase *的值,该值不如CountryCode *

所以:

self = (CountryCode *) [super initWithCode:code len:len];

但你应该做的是将返回类型设置为(id)。这就是通常在Objective-C中完成的。

答案 1 :(得分:4)

使用(id)作为返回值类型。

Objective-C不支持协变声明。考虑:

@interface NSArray:NSObject
+ (id) array;
@end

现在,您可以在+arrayNSArray上致电NSMutableArray。前者返回不可变数组,后者返回可变数组。由于Objective-C缺乏协变声明支持,如果上述声明为返回(NSArray*),则子类方法的客户端必须转换为`(NSMutableArray *)。丑陋,脆弱,容易出错。因此,通常使用泛型类型是最直接的解决方案。

所以......如果你声明一个返回特定类实例的方法,那么显式地进行类型转换。如果您声明一个将被覆盖的方法,并且该覆盖可能返回子类,则返回子类的事实将向客户端公开,然后使用(id)

指定的初始化程序以相同的方式工作。 -init*方法可以返回几乎任何类型的实例,具体取决于实现的上下文(当然)。因此,初始化方法的返回类型是协变的,因此,您需要使用(id)作为返回类型。

无需提交错误 - 已经有几个。


请注意,LLVM现在有一个instancetype关键字,可用于代替上述声明中的id。这意味着“此方法返回一个实例,该实例通过对其进行调用的类的isKindOfClass:测试”,实际上有效。