Quel différence entre une methode de classe et d'instance ?

zenxzenx Membre
15:53 modifié dans API AppKit #1
Bonjour les ami(e)s !

J'aimerais bien comprendre simplement la diffférence entre une methode de classe et une methode d'instance, le contexte dans lequel on utilise une methode de classe plutôt qu'une methode d'instance, et peut être aussi un exemple de chaque qui illustrerait l'emploi des deux types de methode.

D'avance, un grand merci !  ;)

P.S.: Cela s'applique t il aussi aux variables (variables de classe et d'instance ?!)

Réponses

  • BruBru Membre
    15:53 modifié #2
    Une méthode est une fonction qui va s'appliquer sur quelque chose.
    Le quelque chose, c'est soit un objet (on parle alors d'instance de classe), soit une classe.

    Si la méthode est une méthode d'instance, c'est qu'elle va s'appliquer sur un objet existant.
    Si la méthode est une méthode de classe, elle s'appliquera à  une classe.

    L'exemple concret est la fameuse ligne de création d'un objet :
    [tt]unObjet=[[NSObject alloc] init];[/tt]

    Dans cette ligne, il y a 2 méthodes : alloc et init.

    La première méthode alloc est une méthode de classe (la méthode est appliquée à  NSObject qui est bien le nom d'une classe). Cette méthode demande à  la classe NSObject de créer un objet. Lorsque l'objet est correctement créé, alloc retourne son identifiant.

    La seconde méthode init est une méthode d'instance, car elle s'applique à  un objet (dans l'exemple précédent, l'objet est celui retourné par alloc). Cette méthode demande à  l'objet de s'initialiser correctement.

    .
  • LeChatNoirLeChatNoir Membre, Modérateur
    15:53 modifié #3
    Méthode de classe : appelé sur un objet non instancié.

    Méthode d'instance : l'objet doit forcément être instancié.

    Je crois qu'on parle également de méthode virtuelle pour les méthodes de classe mais la, je m'avance peut être un peu.

    Par exemple, les constructeurs sont par définition des méthodes de classe (l'objet n'existe pas encore et le constructeur va le créer).

    Hope this help.

    [ah ben j'arrive un peu tard...]
  • BruBru Membre
    15:53 modifié #4
    dans 1133173683:

    Méthode de classe : appelé sur un objet non instancié.


    C'est un raccourci un peu rapide...
    La méthode de classe est appellé sur l'objet Classe lui-même (et donc, effectivement, n'utilise pas d'objet instancié).

    .
  • AliGatorAliGator Membre, Modérateur
    novembre 2005 modifié #5
    Pour compléter les 2 réponses (merci l'avis de grillade ;)) j'ajouterai ceci :

    une méthode de classe c'est souvent pour créer ou récupérer une instance. Par exemple alloc est une méthode de classe, tu l'appliques sur une classe comme par exemple [NSString alloc], qui te renverra un objet de type NSString, et surtout pas sur une variable genre [mastring alloc] (*). Un autre exemple de méthode de classe c'est pour récupérer une "sharedInstance" genre [NSNotificationCenter defaultCenter] pour récupérer un objet, qui est ici le centre de notification par défaut.

    Une méthode d'instance c'est une méthode qui s'applique à  un objet, par exemple il est exclus d'écrire [NSString init] car init est une méthode d'instance, donc qui doit s'appliquer sur un objet et non sur une classe comme ici la classe NSString. Y'a des chances que ce genre de ligne te génère une erreur de compilation d'ailleurs, j'imagine.

    Et surtout pour rajouter qqch qui n'a pas encore été dit, pour les variables oui c'est pareil. Une variable d'instance est une variable qui est propre à  un objet : c'est à  dire que pour chaque objet créé la variable peut prendre une valeur différente d'un objet à  un autre. Une variable de classe est une variable dont la valeur est commune à  tous les objets de cette classe, et qui aura la même valeur d'un objet à  un autre.
    Par exemple j'imagine que dans la classe NSNotificationCenter il existe une variable de classe (dont on ne connais pas le nom car il n'est pas donné dans la doc) qui mémorise le centre de notification par défaut. Et la méthode de classe "defaultCenter" de cette classe NSNotificationCenter, elle ne fait que retourner la valeur de cette variable (genre "return _defaultCenter;")

    (*)enfin si on peut faire ça mais c'est dans des cas très particuliers (objet classe) qui sont loin d'être utilisés tous les jours et qui est un concept peut être un peu tôt à  aborder ;)
  • zenxzenx Membre
    15:53 modifié #6
    Merci beaucoup pour vos explications et vôtre réactivité !. Je me pose à  nouveau une question :

    Pour l'illustrer, je vais prendre un exemple :

    - (void)rond {
     
      int rayon = 20;
      int r = rayon;

    + (void)changerRayon:int newrayon {
     
      r = newrayon; 

    }

    Bon je ne sais pas si mon code est correct, mais en fait c'est pour savoir si dans mon cas précis, si je crée 2 instances de ma classe rond1 et rond2, est ce qu'en envoyant le message [rond1 changerRayon:30] je change aussi la valeur de la variable de mon objet rond2, ou bien je change seulement la valeur par défaut des prochaine instances de ma classe, ou tout simplement ça ne marche pas du tout ?.
  • MalaMala Membre, Modérateur
    15:53 modifié #7
    Je crois qu'on parle également de méthode virtuelle pour les méthodes de classe mais la, je m'avance peut être un peu.
    Les méthodes de classe seraient plutôt assimilables à  des méthodes statiques comme en C++.
  • AliGatorAliGator Membre, Modérateur
    15:53 modifié #8
    Et bien comme r et rayon sont des variables d'instance, en changeant la valeur de r pour une instance tu ne changes pas la valeur de r pour l'autre instance : c'est ce que j'explique dans mon post à  ralonge plus haut.

    Une variable d'instance est propre à  un objet : chaque objet peut avoir une valeur différente pour cette variable d'instance.
    Ils possèdent tous la propriété (la variable d'instance), mais poru chaque objet elle peut avoir des valeurs différentes.

    Exemple : tu te fabriques une classe voiture, et tu lui rajoutes une variable d'instance "couleur"... et bien -- et encore heureux -- chaque voiture aura une couleur, mais toutes les voitures ne sont pas obligées d'avoir la même !

    Par contre ton code pour la méthode "rond" me gêne... Il ne renvoie rien ? Son nom n'est pas très explicite il ne crée pas un nouveau rond, il modifie juste ses réglages avec une valeur fixe... et en plus rayon et r ne sont pas des variables d'instance, mais jsute des variables temporaires créées dans le corps de ta fonction "rond" et qui seront donc détruites dès la sortie (l'execution) de cette méthode !

    Je pense que ce que tu souhaitais faire c'est (1) créer une classe "Rond" qui possède une variable d'instance "rayon" (propriété de tes objets Rond : un rond est entre auters défini par son rayon, ce qui justifie la variable d'instance)... puis (2) surcharger la méthode "init" pour que par défaut lors de l'initialisation d'un nouveau objet de classe "Rond", son rayon soit initialisé à  la valeur 20 !
    @interface Rond : NSObject<br />{<br />&nbsp;  int rayon;<br />&nbsp;  int x;<br />&nbsp;  int y;<br />}<br />@end<br /><br />// dans le .m<br />@implementation<br />- (Rond) init<br />{<br />&nbsp; self = [super init]; // toujours appeler la méthode de la classe parent quand on surcharge<br />&nbsp; if (self) // vérifier que ça a bien marché, par principe<br />&nbsp; { // et fixer alors les valeurs par défaut<br />&nbsp; &nbsp; x = 0;<br />&nbsp; &nbsp; y = 0;<br />&nbsp; &nbsp; rayon = 20<br />&nbsp; } // end if<br />&nbsp; return self; // retourner l&#39;objet créé<br />}<br />@end
    
    Tu peux aussi te créer une méthode "initWithRayon:CenterX:CenterY:" (voire même des méthodes de commodité qui gèrent l'autorelease, mais là  je pense pas que tu sois prêt vu que tu ne maà®trises pas encore la gestion de la mémoire).
  • AliGatorAliGator Membre, Modérateur
    15:53 modifié #9
    dans 1133176603:

    Je crois qu'on parle également de méthode virtuelle pour les méthodes de classe mais la, je m'avance peut être un peu.
    Les méthodes de classe seraient plutôt assimilables à  des méthodes statiques comme en C++.
    En effet et les méthode virtuelles n'ont rien à  voir !

    Ce sont, pour information, des méthodes qui n'ont pas d'implémentation (et qui ne peuvent donc pas être appelées directement ;)), c'est à  dire pas de code défini. Elles servent juste à  signaler que la classe répond à  cette méthode, mais pour l'utiliser il faut qu'elle soit définie dans une sous-classe.
    Les classes possédant des méthodes virtuelles sont des classes abstraites : elles ne peuvent être utilisées directement, il faut les sous-classer et définir le code de ces méthodes virtuelles dans les sous-classes pour pouvoir les utiliser.

    Par exemple on pourrait très bien imaginer une clase abstraite "figure" avec une méthode virtuelle "aire" (virtuelle donc qui n'a pas de code au niveau de la classe "figure", en effet on ne sait pas comment calculer l'aire d'une figure quelconque, il faut savori de quelle figure il s'agit. mais on sait que toute figure fermée a une aire donc il est logique que la méthode permettant d'en renvoyer sa valeur soit au niveau de la classe mère commune à  toutes les figures.
    Ensuite, on peut créer une classe "rectangle" de même qu'une classe "rond" et "triangle" dérivant toutes de la classe "figure". Chaque classe aura à  définir un code pour la méthode "aire", qui sera différent selon la sous-classe (différent selon le type de figure).
    Il est alors possible de créer des objets de type rectangle, rond ou triangle (mais pas de créer des objets ayant pour classe "figure" directement, car c'est une classe abstraite). Et on pourra très bien faire :
    Figure* f;<br />Rectangle* r = [[Rectangle alloc] init]; // création d&#39;un rectangle aux dimensions par défaut (si on a bien surchargé le init de la classe rectangle)<br />int a = [r aire]; // ça pas de souci<br />f = r; // on a le droit car rectangle est un type particulier (une sous-classe) de Figure<br />Triangle* t = [[Triangle alloc] init]; // création d&#39;un triangle aux dimensions par défaut<br />f = t; // pas de soucis, Triangle est une sous-classe de Figure<br />[f aire]; // on a le droit d&#39;appeler aire même si c&#39;est une méthode virtuelle de la classe Figure, c&#39;est là  tout son intérêt d&#39;ailleurs : cela va automatiquement appeler le code de la méthode &quot;aire&quot; de la classe &quot;Triangle&quot; parce que f est en particulier un Triangle.<br />// f = [[Figure alloc] init]; // ah, là , par contre, pas le droit !<br /><br />[r release]; // on a alloué r, c&#39;est à  nous de le libérer<br />[t release]; // on a alloué t, c&#39;est à  nous de le libérer<br />// [f release]; // (si le [[Figure alloc] init] avait été valable, on aurait eu à  faire ça aussi car pour chaque alloc ou retain il faut au release)
    
  • LeChatNoirLeChatNoir Membre, Modérateur
    15:53 modifié #10
    Ok autant pour moi !
    Merci des explications.
    En résumé :
    * méthode virtuelle et classe absraites sont à  sous classer,
    * variable de classe = variable partagée par tous les objets de cette classe.

    Mais du coup, comment se déclare une variable de classe ?

  • MalaMala Membre, Modérateur
    novembre 2005 modifié #11
    * variable de classe = variable partagée par tous les objets de cette classe.

    Mais du coup, comment se déclare une variable de classe ?

    Et bien c'est comme pour les méthodes statiques auxquelles je faisais allusion en C++.

    Une méthode statique (ou méthode de classe en Obj-C) c'est une méthode qu'on appele indépendament de l'instanciation. Ok?

    Et bien pour tes variables de classe c'est la même chose. Si tu veux avoir une variable de classe, il te suffit de la déclarer en variable statique.
    static int MaVariableStatique;
    

    Et bien sûr, tu créeras Les méthodes de classes qui vont bien pour la manipuler.
  • AliGatorAliGator Membre, Modérateur
    novembre 2005 modifié #12
    En fait le terme "variables de classes" (par opposition aux "variables d'instance") est un peu un raccourci, c'est un abus de langage.
    En réalité en Objective-C il n'existe pas de "variables de classes", on ne peut pas rajouter de variables à  l'objet classe lui-même.

    Le truc pour contourner ça c'est les variables statiques. Tu crées une variable globale ou mieux, une variable interne à  la fonction mais en la précisant "static", ce qui permet de faire en sorte (statut un peu particulier, c'est pas forcément une bonne idée d'introduire cette notion si tôt mais tant pis) que lors du prochain appel elle se rappelle son ancienne valeur (en fait c'est une variable globale mais qui n'est accessible que dans le scope de la fonction, ce qui évite les risques de modifications extérieures).
    Et ensuite tu crées une méthode par exemple :
    <br />+ (MaClasse)sharedInstance<br />{<br />&nbsp; static MaClasse _sharedInstance = nil; // nil car par défaut pas encore créée<br /><br />&nbsp; if (_sharedInstance == nil) _sharedInstance = [[self alloc] init];<br />&nbsp; return _sharedInstance;<br />}
    
    Voilà  l'idée ;)
    Au premier appel _sharedInstance vaudra "nil", mais aux appels suivants, (et ce uniquement parce que _sharedInstance est déclaré avec le mot clé "static"), elle se rappellera sa valeur (qui ne sera plus "nil" à  cause du alloc/init effectué lors du premier appel) !

    quelques infos par là  (en anglais)
    [EDIT] ah et y'a ça aussi, et en français, lui ;)
  • zenxzenx Membre
    15:53 modifié #13
    J'aimerais vous remercier chaleureusement pour toutes ces explications. Merci à  tous les contributeurs et particuliérement à  Aligator pour ses interventions riche en démonstrations et en informations !. 
Connectez-vous ou Inscrivez-vous pour répondre.