2

在我的程序中,我有一个类,比如ClassA。我想创建派生类,比如ClassB。我的程序有函数返回ClassA的实例,在某些情况下,我想使用这些返回来创建ClassB的实例。做天真的向下转换不会导致任何编译器错误,但是运行时错误会蔓延。这似乎与关于投射指针与对象的问题有关 - 无论如何,从我读过的内容来看,这是错误的事情在这种情况下做。Objective-C继承;从父类向下转换/复制到派生类

然后,我试图模仿C++的复制构造函数,但复制的变量超出了范围或被释放,从而导致运行时错误。

我也考虑过使用类别,但是这似乎并不正确,原因有二:

  1. 首先,我不能与类别和东西添加新的类成员将得到一个有点令人费解,如果我能不要这样做。
  2. 就在我可以告诉通过类别添加的方法可用于该类的所有实例。严格来说,这不是一个问题,但它并不适合我,因为我想添加的方法的某些方面会在一般环境中突破;即它们对于我需要用这些类型的对象所做的某种特定方式是特定的。

我还在学习Objective-C。我知道这个论坛有一些类似的问题,但是答案要么导致类别和死胡同,要么没有太多的帮助,所以我觉得我应该简单地重新发布。

回答

1

听起来好像有一种方法返回ClassA的实例,但您希望它返回ClassB的实例。

转换返回值不起作用的原因是因为方法返回的实例实际上并不是ClassB的实例 - 它实际上只是ClassA的一个实例。确定演员本身将“工作”,但底层实例没有必要的数据来正确处理ClassB的成员。

假设您不能(或不想)更改返回ClassB实例的方法,则一个选项(除Categories)将修改ClassB以获取ClassA的实例。 ClassB将覆盖由ClassA实现的所有方法,并且最初推迟传递给ClassA的实例。例如:

@implementation ClassB 
- (id)initWithClassA:(ClassA*)a 
{ 
    self = [super init]; 
    if(!self) 
    { 
     return nil; 
    } 

    myClassA = [a retain]; 

    return self; 
} 

- (void)dealloc 
{ 
    [myClassA release]; 
} 

- (void)ClassAMethod1 
{ 
    [myClassA ClassAMethod1]; 
} 

- (int)ClassAMethod2 
{ 
    return [myClassA ClassAMethod2]; 
} 

- (void)ClassBMethod1 
{ 
    // implement the method here 
} 
@end 

然后,您将使用原始方法返回的ClassA实例创建ClassB的实例。这基本上包装了ClassA的原始实例,并将其转换为ClassB的实例。

+0

这似乎可以工作。我唯一担心的是,由于我没有编写ClassB,它的结构可能会在以后的版本中发生变化,于是我不得不重新编写这个类。虽然我不认为这是一个问题,但我很好奇它是否有办法解决问题。 – Paul 2011-05-29 20:57:16

+0

@Paul:“我只关心它,因为我没有写'ClassB' ...”。在你的问题中,你陈述了“'我想创建一个派生类,比如ClassB'”,这听起来好像你**完全控制它。也许你可以编辑你的问题,使其更清楚? – NSGod 2011-05-30 00:05:25

0

您是否尝试过使用id类型?任何类型的对象都可以分配给它。

+0

我不太清楚你的意思。也许我只是在密集,你能提供某种例子吗? – Paul 2011-05-29 20:57:58

1

比方说ClassAClassBClassC定义如下:

@interface ClassA : NSObject { 

} 
- (void)methodA; 
@end 

@interface ClassB : ClassA { 

} 
- (void)methodB; 
@end 

@protocol ClassCProtocol <NSObject> 
- (void)protocolMethodC; 
@end 

@interface ClassC : ClassA <ClassCProtocol> { 

} 
@end 

为了使事情变得有趣,我还定义了一个@protocol名为ClassCProtocol<NSObject>协议继承,以及一个ClassC对象是ClassA的一个子类,并符合<ClassCProtocol>协议(所有真正意思是符合协议的任何对象都保证实现-protocolMethodC方法)。

首先要注意的是,在Objective-C中,与C++中的派生类没有同样的意义:只有单一继承,所以我们通常谈论的是ClassBClassA的子类或ClassCClassA的子类。

然后采取下面的代码,假设MDLoadObject()是将返回基于力所能及的情况下的ClassAClassB,或ClassC实例的功能:

ClassA *MDLoadObject() { 
    ClassA *object = nil; 
    if (...) { 
     object = [[[ClassA alloc] init] autorelease]; 
    } else if (...) { 
     object = [[[ClassB alloc] init] autorelease]; 
    } else { 
     object = [[[ClassC alloc] init] autorelease]; 
    } 
    return object; 
} 

@interface MDAppController : NSObject { 

} 
- (void)loadObject:(id)sender; 
@end 

@implementation MDAppController 

- (void)loadObject:(id)sender { 
    ClassA *instanceOfClassABorC = MDLoadObject(); 

    if ([instanceOfClassABorC isKindOfClass:[ClassB class]]) { 
     [(ClassB *)instanceOfClassABorC methodB]; 
    } else if ([instanceOfClassABorC isKindOfClass:[ClassC class]]) { 
     [(ClassC *)instanceOfClassABorC protocolMethodC]; 
    } else if ([instanceOfClassABorC respondsToSelector:@selector(protocolMethodC)) { 
     [(ClassC *)instanceOfClassABorC protocolMethodC]; 
    } else { 

    } 
} 
@end 

由于类ClassBClassC最高的共同祖先ClassA,我们定义MDLoadObject()函数返回ClassA的实例。 (请记住,在单一继承中,ClassBClassC的所有实例也保证为ClassA的实例)。

然后,-loadObject:方法显示了Objective-C的活力,并且您可以通过几种方法查询此时MDLoadObject()函数返回的对象类型。需要注意的是-loadObject:方法也没有石膏被写入,它会在运行时运行得很好:

- (void)loadObject:(id)sender { 
    ClassA *instanceOfClassABorC = MDLoadObject(); 

    if ([instanceOfClassABorC isKindOfClass:[ClassB class]]) { 
     [instanceOfClassABorC methodB]; 
    } else if ([instanceOfClassABorC isKindOfClass:[ClassC class]]) { 
     [instanceOfClassABorC protocolMethodC]; 
    } else if ([instanceOfClassABorC respondsToSelector:@selector(protocolMethodC)) { 
     [instanceOfClassABorC protocolMethodC]; 
    } else { 

    } 
} 
4

在我的节目,我有一类,说ClassA的。我想创建一个派生类,比如ClassB。

@class MONClassA; 

@interface MONClassB : MONClassA 
{ 
    int anotherVariable; 
} 

//... 
- (id)initWithMONClassA:(MONClassA *)classA anotherVariable:(int)anotherVar; 

@end 

我的程序有返回ClassA的实例功能,并在某些情况下,我想用这些收益来创建ClassB的实例。

你会做它在C++(因为它听起来好像是你的背景)同样的方式,促进了新的实例类型:

//... 
MONClassA * a = SomeLibFunction(); 
MONClassB * b = [[MONClassB alloc] initWithMONClassA:a anotherVariable:???]; 
//... 

做天真的向下转换不会导致任何编译器错误,但是运行时错误蔓延。这似乎与关于投掷指针和对象的问题有关 - 无论如何,从我读过的内容来看,在这种情况下这是错误的。

正确的 - 这是错误的做法。

我然后试图模仿C++的拷贝构造函数,但被复制传递超出范围或发布的变量,从而再次导致运行时错误。

看到上面的实施情况,看看如何促进在objc类型。这当然假设你还将为初始化定义一个合适的实现(相当于你的cpp构造函数和拷贝构造函数)。

我使用类别也算不过这似乎并不正确......

那么你的直觉可能是正确的。这种语言功能经常被滥用。

+0

什么是“MONClassB”的超类(截至目前,没有定义超类)? – NSGod 2011-05-30 06:43:11