+ Répondre à la discussion
Affichage des résultats 1 à 8 sur 8
  1. #1
    Nouveau Membre du Club
    Homme Profil pro
    Enseignant
    Inscrit en
    avril 2012
    Messages
    27
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Enseignement

    Informations forums :
    Inscription : avril 2012
    Messages : 27
    Points : 35
    Points
    35

    Par défaut Types tagged et liaison dynamique

    Bonjour, je me pense ces derniers sur les types tagged. Et je me posais une question : est-il possible avec l'attribut 'class ou un pointeur sur classe, de disposer d'un objet dont le type pourrait varier ? Exemple, j'ai les classes et méthodes suivantes :

    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    type Voiture is tagged record
       puissance : natural ; 
       marque : string(1..20) ; 
    end record ; 
    function init_voiture(p:natural ; m : string) return Voiture ; 
    procedure rouler(V : Voiture) ;
    
    type Limousine is new Voiture with record
       longueur : float ; 
    end record ; 
    function init_limousine(p:natural ; m : string ; l : float) return limousine ; 
    overriding procedure rouler(V : Limousine) ;
    Puis dans mon programme je voudrais avoir ceci :

    Code :
    1
    2
    3
    4
    5
    6
    put_line("voulez-vous une voiture ou une limousine?");
    get(choix) ; skip_line ;
    if choix = 'L'
       then MaVoiture := init_limousine(...) ; 
       else MaVoiture := init_voiture(...) ; 
    end if ;
    De même, si je déclare MaVoiture comme étant de type Voiture'class, est-il possible d'écrire ensuite MaVoiture.rouler sans avoir à spécifier de quelle méthode rouler je parle ? Bref, comment faire pour que le choix de la méthode se fasse à l'exécution et non à la compilation ?

    Merci d'avance.

  2. #2
    Membre éclairé Avatar de Blackknight
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    février 2009
    Messages
    196
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Seine Maritime (Haute Normandie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : février 2009
    Messages : 196
    Points : 331
    Points
    331

    Par défaut

    Normalement (parce que j'ai pas vérifié et que je maîtrise pas bien tout ça), ça marche mais il va falloir utiliser un accès sur un objet de classe Voiture pour déclarer Ma_Voiture car les objets de classe sont indéfinis.
    Pour plus d'info, regardes le wikibook qui va bien.

  3. #3
    Nouveau Membre du Club
    Inscrit en
    octobre 2010
    Messages
    21
    Détails du profil
    Informations forums :
    Inscription : octobre 2010
    Messages : 21
    Points : 29
    Points
    29

    Par défaut

    Bonjour,

    Dans le rationale d'ada 2005 écrit par John Barnes, ce dernier précise bien que l'écriture préfixée n'est "que" du sucre syntaxique pour ne pas passer par l'arborescence des paquetages (la notation préfixée n'étant d'ailleurs utilisable que si le paquetage est "use"). Cette méthode ne permet donc pas de faire de l'aiguillage dynamique à l'exécution, même si ça le feint relativement bien car le codeur n'a pas à changer le code s'il change le type de la variable, tant que les méthodes appelées sont définies à ce niveau de l'héritage.

    L'aiguillage dynamique ne se fait que via l'appel de méthodes contenant une variable de type Type'class. L'attribut class décrivant l'appartenance à l'arborescence descendante du type attributaire, il est cette fois impossible de savoir quelle(s) méthode(s) on va appeler sur quel type précis, donc plus de notation préfixée.
    Il est important de noter que seuls des appels à des méthodes d'instances au sein d'une méthode de classe sont aiguillés, il n'y a pas d'aiguillage sur la méthode de classe elle-même vu qu'elle est en exemplaire unique.

    EDIT : il semblerait que j'ai cliqué sur envoyer plutôt que visualiser... En espérant que mes explications sont claires donc.

  4. #4
    Membre éclairé Avatar de Blackknight
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    février 2009
    Messages
    196
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Seine Maritime (Haute Normandie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : février 2009
    Messages : 196
    Points : 331
    Points
    331

    Par défaut

    Jaizu, le passage que tu cites :
    L'aiguillage dynamique ne se fait que via l'appel de méthodes contenant une variable de type Type'class.
    me semblait bizarre alors j'ai vérifié.
    L'usage d'un paramètre de la forme Type'Class pour une procédure ne se justifie que lorsque l'on veut faire une procédure s'appliquant à l'ensemble des objets d'un même arbre d'héritage.

    Ainsi, voici un code simpliste (à scinder en morceaux avec gnatchop) pour illustrer la question de Sigurd9. Il n'y a pas de paramètre de classe mais seulement une variable initialisée comme telle.
    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    with Ada.Text_Io; use Ada.Text_Io;
    
    package body Voit is
    
       function init_voiture(p:natural) return Voiture is 
       begin
          return Voiture'(Puissance => P);
       end Init_Voiture;
       
       procedure rouler(V : in Voiture) is
       begin
          Put_Line("La voiture de puissance " & Natural'Image(V.Puissance) & " roule");
       end Rouler;
    end Voit;
    
    package Voit is
       type Voiture is tagged record
          puissance : natural ; 
       end record ; 
       
       function init_voiture(p:natural) return Voiture;
       
       procedure rouler(V : in Voiture);
    
    end Voit;
    
    with Ada.Text_Io; use Ada.Text_Io;
    
    package body Limo is
    
       ------------------
       -- Init_Voiture --
       ------------------
    
       overriding function Init_Voiture (P:Natural) return Limousine is
       begin
          return Limousine'(P,2.0);
       end Init_Voiture;
    
       --------------------
       -- init_limousine --
       --------------------
    
       function init_limousine (p:natural; l : float) return Limousine is
       begin
          return Limousine'(P,L);
       end init_limousine;
    
       ------------
       -- rouler --
       ------------
       overriding
       procedure rouler (V : in Limousine) is
       begin
          Put_Line("la limo roule");
       end rouler;
    
    end Limo;
    
    with Voit; use Voit;
    
    package Limo is
       type Limousine is new Voiture with record
          longueur : float; 
       end record ; 
       
       Overriding function Init_Voiture(P:Natural) return Limousine;
       
       function Init_Limousine(P:Natural; L:Float) return Limousine;
       
       overriding procedure rouler(V : in Limousine);
    
    end Limo;
    
    with Ada.Text_Io; use Ada.Text_Io;	
    with Voit; use Voit;
    with Limo; use Limo;
    
    procedure TestDispatch is
       
       MaVoiture : Voiture := Init_Voiture(12);
       UneVoiture : Voiture'class := Init_Limousine(25,24.3);
    begin
       Rouler(Mavoiture);
       Rouler(Unevoiture);
    end Testdispatch;
    Bon, c'est pas super beau mais ça compile et ça fonctionne.
    Par contre, j'ai re-découvert que je devais surcharger init_voiture dans le paquetage Limo.
    Merci le compilo.

    Par contre, encore une fois si une méthode devait utiliser la fonction Rouler sans connaître le type exact à lui passer, il faudrait que cette fonction prenne un paramètre de la forme Voiture'Class pour pouvoir s'appliquer à tous les objets se trouvant dans l'arbre d'héritage de Voiture.

  5. #5
    Nouveau Membre du Club
    Homme Profil pro
    Enseignant
    Inscrit en
    avril 2012
    Messages
    27
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Enseignement

    Informations forums :
    Inscription : avril 2012
    Messages : 27
    Points : 35
    Points
    35

    Par défaut

    Donc si j'ai bien compris, écrire "MaVoiture : T_Voiture'class" n'a d'intérêt que pour mes méthodes (afin qu'elles s'appliquent à l'intégralité de la classe, sans les soucis liés à l'héritage). Lorsque j'écris mon programme principal, MaVoiture peut-être déclarée de type T_Voiture'class mais doit nécessairement être initialisée ce qui impose qu'elle soit dès le départ de type T_Voiture ou T_Limousine.

    Et si j'utilise un pointeur sur classe, je devrai préciser l'origine de la méthode.

  6. #6
    Membre éclairé Avatar de Blackknight
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    février 2009
    Messages
    196
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Seine Maritime (Haute Normandie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : février 2009
    Messages : 196
    Points : 331
    Points
    331

    Par défaut

    Et si j'utilise un pointeur sur classe, je devrai préciser l'origine de la méthode.
    De toutes façons, il y a bien un moment ou un autre où il faudra dire de quel type est ta voiture, non ?

    Ce que je voulais dire, c'est que si tu décides de faire une fonction ou une procédure qui s'applique à tout type de voiture, tu devras alors le préciser dans sa signature afin de faire l'aiguillage dynamique. Par exemple, je veux tester un ensemble de voitures et donc je dois les faire rouler, je devrais écrire quelque chose comme :
    Code :
    1
    2
    3
    4
    5
    procedure tester(la_voiture_a_tester : in Voiture'Class) is
    begin
            rouler(la_voiture_a_tester);
    end tester;
    Dans ce cas, si la voiture passée en argument est de type Voiture, on appellera bien la méthode rouler de Voiture et si c'est une Limousine, ce sera bien celle de... Limousine.

    Après pour ce qui est de ton pointeur, cela te permettra de retarder l'instanciation de ton objet et donc de de le faire en fonction du retour de l'entrée utilisateur. Il n'y a donc pas de problème

    D'ailleurs, j'ai fait un petit bout de code à l'arrache (en clair, y a certainement une autre solution plus propre) :
    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    with Ada.Command_Line; use Ada.Command_Line;
    
    with Ada.Text_Io; use Ada.Text_Io;	
    with Voit; use Voit;
    with Limo; use Limo;
    
    procedure TestDispatch is
       
       type Voiture_Access is access all Voiture'Class;
       
       MaVoiture : Voiture := Init_Voiture(12);
       UneVoiture : Voiture'class := Init_Limousine(25,24.3);
       
       TempLimo : aliased Limousine;
       TempVoiture : aliased Voiture;
       
       Ptr : Voiture_Access;
       
    begin
       Rouler(Mavoiture);
       Rouler(Unevoiture);
       
       if (Argument_Count > 0 and then Argument(1) = "1") then
          TempLimo := Init_Limousine(25,32.0);
          Ptr := TempLimo'access;
       else
          tempVoiture := Init_Voiture(15);
          Ptr := TempVoiture'Access;
       end if;
       
       Rouler(Ptr.all);
          
    end Testdispatch;
    Parce qu'un peu de code vaut mieux qu'un long discours

  7. #7
    Nouveau Membre du Club
    Inscrit en
    octobre 2010
    Messages
    21
    Détails du profil
    Informations forums :
    Inscription : octobre 2010
    Messages : 21
    Points : 29
    Points
    29

    Par défaut

    @Blackknight : Oh, en effet, quelle bourde ! Mes habitudes ont troublé ma mémoire, milles excuses ! J'avais justement en tête la procédure tester, mais mes informations n'en demeurent pas moins inexactes.

    J'ajouterai cependant une précision : la déclaration d'un Type'class (sans pointeur bien entendu) est semblable à un "tampon de type" qui est contraint à "tout ce qu'il y a entre le type racine et le type de l'initialisation". Si on déclare une Voiture'class comme étant une Limousine (via init_Limousine), on peut par la suite changer et la considérer comme une voiture (avec un Init_Voiture par exemple), puis à nouveau comme une Limousine. Ce n'est bien sûr conseillé que lorsqu'on est sûr d'où on met les pieds et il vaut mieux passer par un pointeur pour le typage.

    Sinon, une idée pour avoir une voiture du type qu'on souhaite :

    Code Ada :
    1
    2
    function Fabrique return Voiture'class;

    Qui se révèle par contre dangereux utilisé ailleurs qu'à l'initialisation (TAG_ERROR si la contrainte sur le type est violée).

  8. #8
    Nouveau Membre du Club
    Homme Profil pro
    Enseignant
    Inscrit en
    avril 2012
    Messages
    27
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Enseignement

    Informations forums :
    Inscription : avril 2012
    Messages : 27
    Points : 35
    Points
    35

    Par défaut

    Merci à tous les deux,

    j'ai les idées plus claires maintenant sur ce que je peux (et dois) faire.

+ Répondre à la discussion
Cette discussion est résolue.

Liens sociaux

Règles de messages

  • Vous ne pouvez pas créer de nouvelles discussions
  • Vous ne pouvez pas envoyer des réponses
  • Vous ne pouvez pas envoyer des pièces jointes
  • Vous ne pouvez pas modifier vos messages
  •