2010-06-10 7 views
0

Ok, donc j'utilise Objective-C. Maintenant, dire que j'ai:Obj-c méthode override/problème de polymorphisme

TopClass : NSObject 
- (int) getVal {return 1;} 
MidClass : TopClass 
- (int) getVal {return 2;} 
BotClass : MidClass 
- (int) getVal {return 3;} 

J'ai alors mis des objets de chaque type dans un NSMutableArray et prendre un. Ce que je veux faire est de lancer la fonc getVal sur le type d'objet approprié, mais quand je mets

id a = [allObjects objectAtIndex:0]; 
if ([a isKindOfClass:[TopClass class]]) 
{ 
    int i; 
    i = [a getVal]; 
} 

Je reçois tout d'abord un avertissement sur plusieurs méthodes appelées getVal (probablement parce que le compilateur ne peut pas déterminer le type d'objet réel jusqu'à l'exécution). Mais plus sérieusement, je reçois aussi une erreur "valeur vide non ignorée comme il se doit" et elle ne compilera pas.

Si je n'essaie pas d'utiliser le retour de [un getVal] alors il compile bien, par ex.

[a getval]; //obviously no good if I want to use the return value 

Il travaillera également si j'utilise des déclarations isMemberOfClass pour lancer l'objet à une classe avant d'exécuter la fonction par exemple

if ([a isMemberOfClass:[BotClass]) i = [(BotClass*) a getVal]; 

Mais je ne devrais sûrement pas avoir à faire cela pour obtenir la fonctionnalité dont j'ai besoin? Sinon, je devrai mettre une instruction pour chaque sous-classe, et pire, ajouter une nouvelle ligne si j'ajoute une nouvelle sous-classe, ce qui annule plutôt le point de surcharge de la méthode, n'est-ce pas?

Sûrement il y a un meilleur moyen?

+1

Vous ne devriez jamais nommer une méthode dans Objective-C '-getSomething', vous l'appelez simplement' -quelque chose '. –

Répondre

1

Puisqu'un BotClass est un MidClass et un MidClass est un TopClass, vous pouvez simplement définir le type de a à TopClass*.

TopClass* a = [allObjects objectAtIndex:0]; 
if ([a isKindOfClass:[TopClass class]]) { 
    int i; 
    i = [a getVal]; 
} 

La meilleure façon est d'ajouter à la -getVal@interface et #import il. Alors le compilateur saura que cette méthode est susceptible de retourner un int et ne se plaindra pas même si a est un id. Assurez-vous que le nom de la méthode ne coïncidera pas avec les autres.

(BTW, en ObjC, getters ne sera pas nommé comme -getFoo La convention est simplement appeler -foo..)

+0

Parfait qui a un sens total. J'avais presque essayé cela, mais en passant du tableau à un, donc évidemment exécuter la méthode a seulement utilisé la méthode de TopVal. De cette façon, je suppose que le compilateur sait à quoi s'attendre, mais n'est pas limité par le cast en ignorant les sous-classes. Merci beaucoup – Rod

+0

Je dirais qu'attribuer d'abord à une variable TopClass et vérifier par la suite si l'objet est vraiment * de * ce genre est une idée amusante. Cela marchera comme si c'était juste un pointeur (vous pourriez même utiliser NSArray * a et il compilerait avec un avertissement mais fonctionnerait dans ce cas), mais c'est une bonne dissimulation de l'intention du code. :-) – Eiko

0

Votre code compile sans aucun avertissement:

#import <Foundation/Foundation.h> 


@interface TopClass : NSObject 
{ 
} 

- (int) getVal; 

@end 

@interface MidClass : TopClass 
{ 
} 

- (int) getVal; 

@end 

@interface BotClass : MidClass 
{ 
} 

- (int) getVal; 

@end 


@implementation TopClass 

- (int) getVal { 
    return 1; 
} 

@end 

@implementation MidClass 

- (int) getVal 
{ 
    return 2; 
} 

@end 

@implementation BotClass 

- (int) getVal 
{ 
    return 3; 
} 

@end 


int main (int argc, const char * argv[]) { 
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; 
    NSMutableArray *array = [NSMutableArray array]; 

    [array addObject:[[[TopClass alloc]init]autorelease]]; 
    [array addObject:[[[MidClass alloc]init]autorelease]]; 
    [array addObject:[[[BotClass alloc]init]autorelease]]; 

    for (int objectNumber = 0; objectNumber < [array count]; objectNumber++) { 
     id a = [array objectAtIndex:objectNumber]; 
     if ([a isKindOfClass:[TopClass class]]) 
     { 
      int i = [a getVal]; 
      NSLog(@"%d",i); 
     }  
    } 

    [pool drain]; 
    return 0; 
} 

Le test « isKindOfClass "est toujours vrai dans ce cas, car MidClass et BotClass héritent de TopClass. Etes-vous sûr que le compilateur connaît les signatures de méthode que vous appelez?