假设我有一个名为Parent
的类和两个名为Child1
和Child2
的派生类。
@interface Parent : NSObject {
NSString *fooVariable;
-(void)foo;
}
@end
@interface Child1 : Parent {
-(void)bar1;
}
@end
@interface Child2 : Parent {
-(void)bar2;
}
@end
现在假设我有一个名为foo
的方法,在某些情况下我想将它作为参数传递给Child1
的实例,在其他情况下我想传递Child2
的实例。根据类型我要调用方法bar1
或bar2
。
如何在Objective-c中实现这一目标?
我尝试了什么:
我决定使用以下签名和实现:
-(void)fooWithObject:(Parent *)instance{
if ([instance isKindOfClass:[Child1 class]]){
[instance bar1];
}
else{
[instance bar2];
}
}
所以现在我可以这样做:
Parent *instance = [[Child1 alloc] init];
//This call is supposed to lead to an invocation of bar1 inside the foo method
[self fooWithObject:instance]
instance = [[Child2 alloc] init];
//This call is supposed to lead to an invocation of bar2 inside the foo method
[self fooWithObject:instance]
不幸的是,当我尝试编译我的代码时,编译器抱怨在我的Parent接口中没有声明方法bar1(或bar2)。
根据一些在线教程,您可以执行以下操作,因此从理论上讲,我的方法应该有效:
NSArray *anotherArray = [NSMutableArray array];
// This mutable-only method call is valid but
// produces a compile-time warning
[anotherArray addObject:@"Hello World"];
答案 0 :(得分:3)
一个简单的解决方案是在Parent和children中声明一个bar函数。然后根据传递的类调用相应的bar函数。你可以使用isKindOfClass函数,但这会破坏继承之美。
答案 1 :(得分:3)
如果您认为您需要这样做(并且您必须要求),那么您就不会使用多态。在这种特殊情况下,您应该覆盖两个子节点中的fooWithObject:
并为该实例调用适当的方法。但听起来你的课程结构可能会有更深层次的问题。
答案 2 :(得分:3)
你快到了。在类型检查之后,您也可以安全地转换并使编译器满意:
-(void)fooWithObject:(Parent *)instance {
if ([instance isKindOfClass:[Child1 self]]) {
Child1 *child1Instance = (Child1 *)instance;
[child1Instance bar1];
} else {
Child2 *child2Instance = (Child2 *)instance;
[child2Instance bar2];
}
}
答案 3 :(得分:1)
我倾向于(a)将两个bar
方法命名为相同; (b)为bar
定义Parent
函数,或使用协议:
@protocol Bar <NSObject>
- (void)bar;
@end
@interface Parent : NSObject {
NSString *fooVariable;
}
-(void)foo;
@end
@interface Child1 : Parent <Bar>
@end
@interface Child2 : Parent <Bar>
@end
然后有一个方法:
-(void)fooWithObject:(id<Bar>)instance {
[instance bar];
}
如果你真的需要bar1
和bar2
完全不同的名字(这是真正抽象的方法名称使问题不那么明确的一点),那么你可以做类似的事情:
@interface Parent : NSObject {
NSString *fooVariable;
}
-(void)foo;
@end
@interface Child1 : Parent
- (void)bar1;
@end
@interface Child2 : Parent
- (void)bar2;
@end
然后,
-(void)fooWithObject:(Parent *)instance {
if ([instance isKindOfClass:[Child1 class]]) {
[(Child1 *)instance bar1];
}
else if ([instance isKindOfClass:[Child1 class]]) {
[(Child2 *)instance bar2];
}
}
或者
-(void)fooWithObject:(Parent *)instance {
if ([instance respondsToSelector:@selector(bar1)]) {
[(Child1 *)instance bar1];
}
else if ([instance respondsToSelector:@selector(bar2)] {
[(Child2 *)instance bar2];
}
}