为什么gcc用'self = [super initDesignatedInit]'来警告不兼容的结构赋值;''调用派生类? [英] Why does gcc warn about incompatible struct assignment with a `self = [super initDesignatedInit];' call in derived class?

查看:104
本文介绍了为什么gcc用'self = [super initDesignatedInit]'来警告不兼容的结构赋值;''调用派生类?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

@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]; //这里
返回自我;
}
@end

在标有here的行上,我得到以下gcc警告:



警告:不兼容Objective-C类型指定'struct ASCIICodeBase *',预期'struct CurrencyCode *'

这段代码有什么问题,或者我应该有 ASCIICodeBase return ID ?或者在这里行上使用强制转换?

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



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

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

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



因此...如果您声明一个返回特定类的实例的方法,则类型转换明确。如果你声明了一个将被覆盖的方法,并且覆盖可能返回一个子类,它返回一个子类的事实将暴露给客户端,然后使用(id)



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



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




请注意,LLVM现在有一个 instancetype 关键字,可用于替换声明中的 id 像上面那样。这意味着这个方法有效地返回一个实例传递一个 isKindOfClass:测试类的实际名称。


I have the following base/derived class setup in 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

On the line marked "here", I get the following gcc warning:

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

Is there something wrong with this code or should I have the ASCIICodeBase return id? Or maybe use a cast on the "here" line?

解决方案

Use (id) as the return value type.

Objective-C doesn't support covariant declarations. Consider:

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

Now, you can call +array on both NSArray and NSMutableArray. The former returns an immutable array and the latter a mutable array. Because of Objective-C's lack of covariant declaration support, if the above were declared as returning (NSArray*), clients of the subclasses method would have to cast to `(NSMutableArray*). Ugly, fragile, and error prone. Thus, using the generic type is, generally, the most straightforward solution.

So... if you are declaring a method that returns an instance of a specific class, typecast explicitly. If you are declaring a method that will be overridden and that override may return a subclass and the fact that it returns a subclass will be exposed to clients, then use (id).

Designated initializers work the same way. An -init* method may return an instance of just about any type, depending on context of implementation (of course). Thus, the return type of initialization methods is covariant and, as a result, you need to use (id) as the return type.

No need to file a bug -- there are several already.


Note that LLVM now has an instancetype keyword that can be used in place of id in a declaration like the above. It means "this method returns an instance that passes an isKindOfClass: test of the class upon which it was called", effectively.

这篇关于为什么gcc用'self = [super initDesignatedInit]'来警告不兼容的结构赋值;''调用派生类?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆