[Résolu] héritage

ancrouancrou Membre
avril 2008 modifié dans Vos applications #1
Bonjour,

J'ai une classe un peu trop chargé donc je veux l'éclater. Pour expliquer, je vais parler d'animaux,de chat et chien  ::)
Pour le moment, c'est ma tête qui éclate  :crackboom:-

Le Monde.m il hérite de NSObject
<br />@implementation Monde<br />Animal* annimal = [[[Animal alloc] initWithId:idA :nbPatte] autorelease];<br />[listeSection addObject: annimal];<br /><br />//....<br /><br />switch([[listeSection objectAtIndex:loop] idA]){<br />			case 0x00:<br />			 if(![(Chien*)[listeSection objectAtIndex:loop] mordre]){<br />					return NO;<br />				}<br />				break;<br />				<br />			case 0x01:<br />				if(![(Chat*)[listeSection objectAtIndex:loop] mordre]){<br />					return NO;<br />				}<br />				break;<br />}<br />@end<br />


Le Animal.h
@interface Animal : NSObject{<br />	<br />} <br />-initWithId:(UI08_)idA&nbsp; :(int) nbPatte;<br />@end


Le Chat.h
#import &quot;Animal.h&quot;<br /><br />@interface Chat : Animal {<br /><br />}<br />-(id)mordre;<br /><br />@end



Je ne sais pas si je suis bien claire  :(

Je vous rassure, je ne manipule pas en réalité des chat chien... mais ça me semble plus simple pour expliquer.

Réponses

  • schlumschlum Membre
    23:55 modifié #2
    Le problème, c'est qu'il n'y a pas de question  :P
  • ancrouancrou Membre
    23:55 modifié #3
    dans 1208435630:

    Le problème, c'est qu'il n'y a pas de question  :P

    Mon problème c'est que ça ne marche pas.

    Peut être en voyant ma structure on me dirait "tu as  :fouf): "

    Peut on allouer puis initialiser un type Animal.
    Puis faire un cast sur Animal en Chat ou Chien et lancer une méthode qui est disponible que dans les classes spécifiques.
    La méthode mordre est disponible que dans Chat et Chien, non dans Animal.

  • Philippe49Philippe49 Membre
    avril 2008 modifié #4
    Voir Class-Clusters , protocoles

    Ta classe Animal définit dans son interface des méthodes communes à  toutes les sous-classes, sans forcément en faire une implémentation précise.

    enum { DOUCEMENT, FORT  } MODE_DE_MORSURE;

    @interface Animal : NSObject
    {
      // variables communes
    }
    -(id) initWithSpeed:(CGFloat) aSpeed;
    -(void) mordre:(MODE_DE_MORSURE) aMode;
    @end


    Chaque sous-classe redéfinit les méthodes dans son implémentation sans avoir besoin de les déclarer dans l'interface

    appel :   Chat * aCat=[[CHAT alloc] initWithSpeed:25.];
  • ancrouancrou Membre
    23:55 modifié #5
    Alors quand je fais :

    Animal* dog = [[[Animal alloc] initWithId:idA :nbPatte] autorelease];<br />[(Chien*)dog mordre]);
    


    Je ne passe pas dans la méthode mordre de ma classe Chien mais dans la méthode mordre de ma classe animal.

  • Philippe49Philippe49 Membre
    avril 2008 modifié #6
    dans 1208440936:

    Alors quand je fais :

    Animal* dog = [[[Animal alloc] initWithId:idA :nbPatte] autorelease];<br />[(Chien*)dog mordre]);
    


    Je ne passe pas dans la méthode mordre de ma classe Chien mais dans la méthode mordre de ma classe animal.


    Oui.
    En objective-C chaque objet possède un champ isa pointant sur l'objet de classe représentant la classe de l'objet.
    Le cast ne change pas ce champ.
    Les messages sont envoyés dynamiquement, si l'objet qui le reçoit sait répondre au message il l'effectue comme il sait l'effectuer. C'est logique : on hérite des manies de ses parents si on ne les a pas réinventées soi-même, pas le contraire, mais chaque génération peut réinventer ...

    #import <Foundation/Foundation.h>

    @interface Animal : NSObject
    {
    }
    -(void) mordre;
    @end

    @interface Chat : Animal
    {
    }
    @end

    @implementation Animal
    -(void) mordre { NSLog(@Ouarf);}
    @end

    @implementation Chat
    -(void) mordre { NSLog(@Miaou);}
    @end

    int main(int argc, char**argv){
    NSAutoreleasePool * pool=[[NSAutoreleasePool alloc] init];
    Chat * minou=[[[Chat alloc] init] autorelease];
    Animal * ours=[[[Animal alloc] init] autorelease];
    [minou mordre];
    [ours mordre];
    [(Chat*) ours mordre];
    [(Animal*) minou mordre];
    [pool release];
    return 0;
    }


    Et les chats font toujours Miaou, les Ours font toujours Ouarf



    % clear;gcc pgm.m -o pgm -framework Foundation
    % pgm
    2008-04-17 17:17:54.723 pgm[770:10b] Miaou
    2008-04-17 17:17:54.724 pgm[770:10b] Ouarf
    2008-04-17 17:17:54.725 pgm[770:10b] Ouarf
    2008-04-17 17:17:54.726 pgm[770:10b] Miaou
    %

  • ancrouancrou Membre
    23:55 modifié #7
    merci beaucoup
    Je vais chercher une autre solution, comme par exemple, faire des alloc  de chien et chat et pas de animal.
  • Philippe49Philippe49 Membre
    avril 2008 modifié #8
    dans 1208446215:

    Je vais chercher une autre solution, comme par exemple, faire des alloc  de chien et chat et pas de animal.


    Fais gaffe, le gouvernement vient d'annoncer que les alloc vont baisser, mais bon peut-être pas pour les chiens et les chats .

    "It is raining Cats and Dogs"

    ou les équivalents :

    It's raining cats and dogs / buckets / stair rods / pitchforks / elephants & giraffes   ;D
    It's a frog strangler,
    It's a frog-strangling-gully-washer,
    It's a frog-strangling downpour
    it's pelting / chucking / pissing / tipping it down
  • AliGatorAliGator Membre, Modérateur
    avril 2008 modifié #9
    Si vraiment tu veux le comportement décrit, il faut travailler directement avec les @selector et les IMP... (voir plus bas)

    Mais avant, il faut réfléchir à  savoir si c'est vraiment judicieux. Ne faut-il pas mieux créer un Chat directement, quitte à  le stocker dans une variable Animal ?
    Ca me parait plus adapté et mieux respecter le principe d'abstraction, et palier à  ton problème :
    Animal* animal; // peut contenir n&#39;importe quel animal, chat chien ou autre<br />animal = [[Chat alloc] init]; // stocké dans une variable &quot;Animal*&quot; mais c&#39;est quand même un vrai Chat<br />[animal mordre]; // si je me trompe pas, ça va appeler la méthode &quot;mordre&quot; de Chat, et non d&#39;animal<br />// car animal contient un objet de type Chat (car on a fait [Chat alloc]), même si ce dernier est stocké dans une variable de type plus générique &quot;Animal*&quot;<br />[animal release];
    
    Comme ça tu peux par exemple dans une classe avoir une variable d'instance de ta classe de type générique "Animal*" et ensuite c'est en au moment de l'allocation (donc création de l'objet que tu stockes dans cette variable) que le type est défini


    ----


    Maintenant si tu veux vraiment appeler la méthode "mordre" de la classe "Chat" sur un objet qui n'en n'est pas forcément un à  l'origine, il suffit de demander à  la classe qui t'intéresse ("Chat" en l'occurence) la méthode appelée quand tu demandes ce @selector sur les objets de classe Chat, puis de l'appeler sur ton autre objet.
    Tout ça est décrit ici dans la doc Apple

    Ca devrait donner un code du genre (non testé) :
    typedef void (*mordre_IMP)(id, SEL); // fonction ne prenant pas d&#39;argument (à  part les deux cachés) et retournant void<br />// récupérer la fonction correspondant au selecteur &quot;mordre&quot; de la classe Chat (ne pas oublier de caster !):<br />mordre_IMP mordre_comme_un_chat = (mordre_IMP)[Chat instanceMethodForSelector:@selector(mordre)];<br /><br />Animal* fauxchat = [[Animal alloc] init]; // c&#39;est un Animal, pas un chat<br />[fauxchat mordre]; // fait &quot;Ouaf&quot; car appelle la méthode &quot;mordre&quot; de... Animal, logique ;)<br />mordre_comme_un_chat(fauxchat, @selector(mordre)); // appelle explicitement le &quot;mordre&quot; de &quot;Chat&quot; sur fauxchat, donc fait &quot;miaou&quot;<br /><br />[chat release];<br />
    
  • Philippe49Philippe49 Membre
    avril 2008 modifié #10
    Sans oublier que dans une de ces méthodes, un chat peut mordre comme un animal :

    @implementation Chat
    -(void) mordre { NSLog(@Miaou);}
    -(void) mordreCommePapa { [super mordre];}
    @end

    Appel
    Chat * chat=[[alloc] init];
    [chat mordreCommePapa];

    ===========================================================

    #import <Foundation/Foundation.h>

    @interface Animal : NSObject
    {
    }
    -(void) mordre;
    @end

    @interface Chat : Animal
    {
    }
    -(void) mordreCommePapa;
    @end

    @implementation Animal
    -(void) mordre { NSLog(@Ouarf);}
    @end

    @implementation Chat
    -(void) mordre { NSLog(@Miaou);}
    -(void) mordreCommePapa { [super mordre];}
    @end

    int main(int argc, char**argv){
    NSAutoreleasePool * pool=[[NSAutoreleasePool alloc] init];
    Chat * minou=[[[Chat alloc] init] autorelease];
    [minou mordre];
    [minou mordreCommePapa];
    [pool release];
    return 0;
    }



    Resultat :

    % pgm
    2008-04-18 06:33:22.618 pgm[218:10b] Miaou
    2008-04-18 06:33:22.620 pgm[218:10b] Ouarf
    %



  • Philippe49Philippe49 Membre
    avril 2008 modifié #11
    dans 1208475108:

       Animal * animal; // peut contenir n'importe quel animal, chat chien ou autre
       animal = [[Chat alloc] init]; // stocké dans une variable "Animal*" mais c'est quand même un vrai Chat
       [animal mordre];


    Pour moi le NSAnimal * animal ne sert que pour la compilation, et à  nous faire de jolis Warnings ... La déclaration ne fait rien du tout sur l'objet en lui-même que l'on manipulera à  l'exécution.

    Le monde est un gigantesque void *, né de void*, et qui y retournera ...   :) :)

    =============================================
    #import <Foundation/Foundation.h>

    @interface Animal : NSObject
    {
    }
    -(void) mordre;
    @end

    @interface Chat : Animal
    {
    }
    @end

    @implementation Animal
    -(void) mordre { NSLog(@Ouarf);}
    @end

    @implementation Chat
    -(void) mordre { NSLog(@Miaou);}
    @end



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

    NSString * ours=[[[Animal alloc] init] autorelease];
    [ours mordre];

    [pool release];
    return 0;
    }


    Exécution :
    % clear;gcc pgm.m -o pgm -framework Cocoa
    pgm.m: In function ‘main':
    pgm.m:30: warning: ‘NSString' may not respond to ‘-mordre'
    pgm.m:30: warning: (Messages without a matching method signature
    pgm.m:30: warning: will be assumed to return ‘id' and accept
    pgm.m:30: warning: ‘...' as arguments.)

    % pgm
    2008-04-18 08:48:25.100 pgm[530:10b] Ouarf
    %

  • AliGatorAliGator Membre, Modérateur
    23:55 modifié #12
    Ben oui c'est le principe de l'envoi dynamique de message en Objective-C, pas besoin de savoir à  la compilation si l'objet va répondre au message pour lui envoyer quand même ;)

    Par contre si tu mets Animal* (et pas NSAnimal* tu l'as rajouté d'où le NS ? :D) et non NSString*, il te fait un warning quand même, alors même que Animal répond lui aussi à  la méthode "mordre" ?? Parce que NSString en effet ne déclare pas "mordre" comme méthode, mais Animal c'est le cas donc il ne devrait pas te mettre de warning, si ? Justement à  cause de l'héritage si tu as bien déclaré tes trucs correctement ?  ???

    Sinon un truc que j'adore dans vos exemples à  vous deux, c'est que vous déclarez une NSAutoreleasePool que vous relâchez à  la fin de votre main, ce qui est normal... mais vous ne faites jamais ni de release, ni d'autorelease sur l'Animal que vous allouez pour l'exemple ;D Je trouve ça assez comique pour le coup  :)
  • Philippe49Philippe49 Membre
    avril 2008 modifié #13
    dans 1208506725:

    Par contre si tu mets Animal* (et pas NSAnimal* tu l'as rajouté d'où le NS ? :D)

    Ok mais NextStep aurait quand même dû penser à  nous fournir une classe aussi importante !!   ;D

    dans 1208506725:

    et non NSString*, il te fait un warning quand même, alors même que Animal répond lui aussi à  la méthode "mordre" ?? Parce que NSString en effet ne déclare pas "mordre" comme méthode, mais Animal c'est le cas donc il ne devrait pas te mettre de warning, si ? Justement à  cause de l'héritage si tu as bien déclaré tes trucs correctement ?  ???

    Pour confirmer tout cela :
    Il n'y a aucun warning avec
    Chat * ours=[[Chat alloc] init];
    [ours mordre];
    ou
    Animal * ours=[[Chat alloc] init];
    [ours mordre];
    ou même
    Animal * ours=[NSString stringWithString:@Balou];
    [ours mordre];

    Ce n'est qu'à  l'exécution que ça coince sur le dernier avec un "unrecognized selector" bien logique.

    D'ailleurs, sur le papier, on peut bein demander à  l'ours Balou de mordre en disant "Miaou", ce n'est qu'à  l'exécution que ça craint !


    dans 1208506725:

    Sinon un truc que j'adore dans vos exemples à  vous deux, c'est que vous déclarez une NSAutoreleasePool que vous relâchez à  la fin de votre main, ce qui est normal... mais vous ne faites jamais ni de release, ni d'autorelease sur l'Animal que vous allouez pour l'exemple ;D Je trouve ça assez comique pour le coup  :)

    C'est un oubli, l'habitude des convenient methods ... Faudrait quand même que je me relise ...
    Bon je corrige pour la post-hérité de ce post.



  • NseaProtectorNseaProtector Membre
    23:55 modifié #14
    Juste pour détendre et parce que c'est vrai:
    Moi ce matin ma voisine (la mère Michelle) est venue me voir parce qu'elle a perdue son chat (lol), une idée ?
    Ok, je sors ->
  • schlumschlum Membre
    23:55 modifié #15
    dans 1208527289:

    Juste pour détendre et parce que c'est vrai:
    Moi ce matin ma voisine (la mère Michelle) est venue me voir parce qu'elle a perdue son chat (lol), une idée ?
    Ok, je sors ->


    Oui, mais la vrai question est... est-ce que tu t'appelles Lustucru ?  ??? :o
  • AliGatorAliGator Membre, Modérateur
    23:55 modifié #16
    C'est un chat qui faisait Miaou, ou un qui faisait Ouaf ?  ;)
  • ancrouancrou Membre
    23:55 modifié #17
    Au final je suis arrivé.
    J'ai mis le temps  ???

    Merci à  tous
Connectez-vous ou Inscrivez-vous pour répondre.