IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage C++ Discussion :

Membre générique dans une classe ("member template")


Sujet :

Langage C++

  1. #1
    Membre à l'essai
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    24
    Détails du profil
    Informations personnelles :
    Âge : 36
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 24
    Points : 18
    Points
    18
    Par défaut Membre générique dans une classe ("member template")
    Bonjour,

    J'ai déclaré une "interface" pour les conteneurs de type LIFO sous la forme d'une classe générique abstraite :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    #ifndef LIFO_H_
    #define LIFO_H_
     
    template<typename T>
    class Lifo {
    public:
        virtual void push(const T&) =0;
        virtual T pop() =0;
        virtual bool isEmpty() const =0;
        virtual int size() const =0;
    };
     
    #endif // LIFO_H_
    Plusieurs classes héritent de la classe générique abstraite Lifo<T> et en définissent les fonctions membres, dont la classe générique BasicStack<T>.

    J'ai ensuite voulu déclaré une classe de test qui pourrait manipuler n'importe quel objet à travers les fonctions membres de l'interface Lifo<T>.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
     
    #ifndef LIFOTEST_H_
    #define LIFOTEST_H_
     
    #include "Lifo.h"
     
    class LifoTest {
    public:
        template<typename T>
        LifoTest(Lifo<T>*);
     
        void run();
    private:
        template<typename T>
        Lifo<T>* container;
    };
     
    #include "LifoTest.tpp"
     
    #endif // LIFOTEST_H_
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    int main() {
        BasicStack<int> pile;
     
        LifoTest test(&pile);
        test.run();
     
        return 0;
    }
    Mais j'ai une erreur à la compilation :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    
    Data member '_container' cannot be a member template
    
    Sachant que le membre _container est l'objet que je souhaite manipuler dans la fonction membre run(). J'ai utilisé un pointeur afin de pouvoir utiliser le polymorphisme.

  2. #2
    Membre expérimenté
    Homme Profil pro
    Chercheur
    Inscrit en
    Mars 2010
    Messages
    1 218
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Chercheur

    Informations forums :
    Inscription : Mars 2010
    Messages : 1 218
    Points : 1 685
    Points
    1 685
    Par défaut
    Bonjour,

    En fait, je pense que ta classe devrait être générique dans ton cas :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    template<typename T>
    class LifoTest {
    public:
        LifoTest(Lifo<T>*);
     
        void run();
    private:
        Lifo<T>* container;
    };

  3. #3
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 629
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 629
    Points : 30 692
    Points
    30 692
    Par défaut
    Salut,

    Tu ne semble pas forcément avoir compris le principe des classes template

    L'idée du paradigme générique est de se dire que si on ne sait pas encore quel type on va manipuler, on sait par contre parfaitement comment on va le manipuler.

    On pourrait dire que cela permet de définir un concept particulier.

    En effet, à partir du moment où tu travaille avec un système LIFO, que tu manipule des téléviseurs, des morceaux de bidoches (gare à ceux qui resteront au fond du congélateur ) ou des voitures n'aura que très peu d'importance: le premier dernier entré sera le dernier sorti.

    Il n'y aura, en outre, aucun intérêt à vouloir le spécialiser plus que cela car, si tu rajoute une fonction sort (par exemple), ce n'est plus du LIFO vu que le dernier entré ne sera plus forcément... le dernier sorti

    Tu peux (pire : tu dois) donc, directement fournir le comportement correct pour les fonctions de ta classe template, et il est absolument inutile de faire croire au compilateur que les différents comportements sont susceptibles d'être modifié par une classe dérivée (vu que, en toute logique, il n'y aura pas de classe dérivée, du moins, dans l'exemple que tu donne ).

    [EDIT] Si tu veux, par exemple, faire en sorte que ta pile maintienne se différents éléments de manière différente en fonction de leur taille, il va falloir passer par ce que l'on appelle des politiques et des traits de politique, mais ca, c'est déjà une technique encore beaucoup plus évoluée

  4. #4
    Membre à l'essai
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    24
    Détails du profil
    Informations personnelles :
    Âge : 36
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 24
    Points : 18
    Points
    18
    Par défaut
    koala01, j'ai l'impression que tu parle plutôt de mon choix de créer une
    interface Lifo<T> que de ma classe LifoTest qui n'est pas une classe générique, mais qui ne doit pouvoir manipuler que des types Lifo<T>.

    J'avoue pas ne pas trop saisir sur quoi porte ta remarque.
    Car, pour moi, l'idée d'utiliser une classe générique pour une pile me semble tout à fait justifié.

  5. #5
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 629
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 629
    Points : 30 692
    Points
    30 692
    Par défaut
    Le fait d'implémenter une pile de manière générique est totalement justifié, je ne dis pas le contraire.

    On peut même envisager de remplir la pile d'objet polymorphes, il n'y a pas de problème de ce coté là non plus.

    Mais vouloir implémenter une pile générique polymorphe n'a strictement aucun sens

    Car, si tu pars sur l'idée de déclarer des fonctions virtuelles dans ta pile, ce n'est pas pour l'utiliser avec des objets polymorphes, c'est pour rendre ta pile polymorphe (au sens objets du terme), mais, quel serait le type de pile qui pourrait hériter d'une pile générique (hormis spécialisation classique pour faire en sorte que la pile manipule des caisses)

  6. #6
    Rédacteur

    Avatar de Davidbrcz
    Homme Profil pro
    Ing Supaéro - Doctorant ONERA
    Inscrit en
    Juin 2006
    Messages
    2 307
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 32
    Localisation : Suisse

    Informations professionnelles :
    Activité : Ing Supaéro - Doctorant ONERA

    Informations forums :
    Inscription : Juin 2006
    Messages : 2 307
    Points : 4 732
    Points
    4 732
    Par défaut
    Dans ta classe LifoTest, comment veux tu que le compilateur trouve tout seul le bon type à donner à container au moment de l'instantiation du template ? Il ne peut pas ! La solution à ceci, cf Aleph69.

  7. #7
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 629
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 629
    Points : 30 692
    Points
    30 692
    Par défaut
    Je vais préciser un peu, pour que tu comprenne:

    Pour gérer ta pile, tu peux décider d'utiliser différentes politiques pour la gestion du contenu de celle-ci, allant du concept d'élément reliés les uns avec les autres au concept de "pool d'allocation", en passant par d'autres encore.

    La manière de déterminer si ta pile est vide, de déterminer le nombre d'objets qu'elle contient, d'ajouter un élément ou de le retirer dépendra, exclusivement, de la politique envisagée.

    Par exemple, si tu utilise un pool d'allocation, le nombre d'élément qu'elle contient correspond à la différence entre l'adresse du dernier élément et celle à laquelle commence le pool, alors que, si tu décide d'utiliser un concept d'éléments dont chacun est relié à son précédent, tu manipulera plutôt un compteur.

    Mais ce genre de gestion se fait... au niveau des template, par exemple sous la forme de:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    /* je considère que PoolAllocator dispose d'une fonction empty ;)
     */
    template<typename T, typename Allocator=PoolAllocator>
    class Lifo
    {
        public:
            bool empty() const{return allocator_.empty();}
        private:
            Allocator allocator_;
    };
    A partir de là:

    Si tu viens à envisager une autre politique de gestion des éléments, il te "suffit" de fournir un nouveau type d'allocateur, et de préciser (comme deuxième type) que c'est celui qu'il faut utiliser.

    Par contre, que tu veuille manipuler des caisses, des boites de concerves, de Truc ou des Bidules ne changera absolument pas la manière de fonctionner de ta pile

    Au niveau de LifoTest, tu sais quel type d'objet ta pile va devoir gérer, et tu as, sans doute, une idée relativement précise de la manière qui sera la plus adéquate de gérer ces éléments (de la politique que tu vas utiliser pour le faire).

    Il te suffira donc, tout simplement, de créer un objet de type Lifo en le spécialisant selon tes besoins:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    class LifoTest
    {
        public:
            Message & top() const{return lifo_.top();}
            bool isEmpty() cosnt{return lifo_.empty();}
            void push(Message const& m){lifo_.push();}
            /* ...*/
        private:
            Lifo<Message, SeparateElement> lifo_;
    };

  8. #8
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 629
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 629
    Points : 30 692
    Points
    30 692
    Par défaut
    Citation Envoyé par Davidbrcz Voir le message
    Dans ta classe LifoTest, comment veux tu que le compilateur trouve tout seul le bon type à donner à container au moment de l'instantiation du template ? Il ne peut pas ! La solution à ceci, cf Aleph69.
    Et encore...

    Pourquoi utiliser un pointeur si tu sais pertinemment quel sera le type réel de T

  9. #9
    Rédacteur

    Avatar de Davidbrcz
    Homme Profil pro
    Ing Supaéro - Doctorant ONERA
    Inscrit en
    Juin 2006
    Messages
    2 307
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 32
    Localisation : Suisse

    Informations professionnelles :
    Activité : Ing Supaéro - Doctorant ONERA

    Informations forums :
    Inscription : Juin 2006
    Messages : 2 307
    Points : 4 732
    Points
    4 732
    Par défaut
    Pourquoi utiliser un pointeur si tu sais pertinemment quel sera le type réel de T
    Il est sans doute tard (quoi que ^^) mais j'ai pas compris le rapport. Et de toute façon, c'est accessoire pour lever le problème de compilation.

    Et puis, si on imagine que ca classe va réaliser une série de teste sur des conteneurs externes (c'est à dire que ce n'est pas elle qui en a la gestion), l'idée de pointeur [1] me semble plutôt appropriée pour pouvoir passer plusieurs conteneurs à l'objet de test.

    1/ Même s'il est vrai qu'un pointeur laisse le doute sur la responsabilité. Une sorte d'objet a sémantique de pointeur alloué sur la pile pour encapsuler ce pointeur aurait été sans doute mieux

  10. #10
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 629
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 629
    Points : 30 692
    Points
    30 692
    Par défaut
    Citation Envoyé par Davidbrcz Voir le message
    Il est sans doute tard (quoi que ^^) mais j'ai pas compris le rapport. Et de toute façon, c'est accessoire pour lever le problème de compilation.
    Pose toi la question de savoir dans quel cas il faut manipuler un pointeur (les cas où tu n'a pas le choix)...

    1- Lorsque tu veux créer une relation entre un contenu et un contenant, tu utilisera un pointeur vers le contenu dans le contenant

    2- Lorsque tu envisage d'utiliser un objet polymorphe, mais, de toutes évidences, ce ne sera pas le cas (car une pile fonctionnera toujours de la même manière)

    3- Quand tu veux utiliser un objet qui peut ne pas exister

    Tu n'es, visiblement dans aucun de ces cas

    Si la pile n'existe que pour servir LifoTest, il serait vraiment dommage de passer par un pointeur, avec tous les problèmes de gestion dynamique de la mémoire que cela sous entend, alors qu'une instance classique de la pile fait si bien l'affaire
    Et puis, si on imagine que ca classe va réaliser une série de teste sur des conteneurs externes (c'est à dire que ce n'est pas elle qui en a la gestion), l'idée de pointeur me semble plutôt appropriée pour pouvoir passer plusieurs conteneurs à l'objet de test.
    La question devient alors: une fois que j'ai créé une instance de LifoTest, en la mettant en relation avec une pile "externe" et que j'en ai géré le contenu, que vais-je faire

    Tu rentres, de toutes évidence, dans un contexte de la création d'une instance très temporaire de LifoTest, dont l'existence est limitée à... la durée d'exécution d'une fonction.

    Crois tu dés lors réellement qu'il soit utile de permettre de changer la pile référencée par LifoTest

    Rien ne te l'interdit dans l'absolu, si ce n'est que tu as le fameux principe de la délégation des tâches qui te conseille de ne pas le faire (si tu es dans une fonction qui doit gérer N piles, le mieux est d'appeler une fonction N fois qui... gérera chaque fois une pile particulière )

    Et il ne faut pas oublier le conseil de n'utiliser l'opérateur "address of" (l'esperluette) que dans tu n'as vraiment pas d'autre choix

    En définitive, on ne peut pas exclure la nécessité d'utiliser un pointeur, mais, dans bien des cas, il serait sans doute largement préférable d'utiliser une... référence pour représenter la pile utilisée (et de modifier le constructeur pour qu'il prenne une référence non constante )

    Tu y gagnera, quoi qu'il arrive, la garantie de non nullité de la référence sur la pile en question, et ce sera déjà pas si mal

  11. #11
    Membre à l'essai
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    24
    Détails du profil
    Informations personnelles :
    Âge : 36
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 24
    Points : 18
    Points
    18
    Par défaut
    Citation Envoyé par koala01 Voir le message
    Mais vouloir implémenter une pile générique polymorphe n'a strictement aucun sens
    Je suis d'accord avec toi. Je pense que j'aurai dû un peu plus préciser pourquoi j'ai choisi cela.
    Comme dans le sujet précédent, ce que je fait n'a pour seul intérêt que l'apprentissage des concepts du C++. J'essaye donc de trouver des manières d'utiliser tout ces concepts.
    Dans ce cas, la création d'une "interface" pour ma pile n'est là que parce que je voulais tester la création d'objets polymorphes. Je voulais en même temps pouvoir définir trois implémentation de mon interface Lifo<T> :
    • la première, qui correspond à celle que j'ai exposé dans le sujet précédent, effectue une réallocation à chaque ajout/suppression d'un élément (je sais, c'est horrible )
    • la seconde, que je n'ai pas encore écrite, est décrite dans ce post
    • et peut-être une troisième qui utiliserait en interne une liste chaînée (que je m'amuserais bien sûr à coder moi même)


    Pour ce qui est de ma classe LifoTest, je suis parti avec une idée de la manière dont je pourrais l'instancier et lancer le test, mais également de la manière de l'implémenter .

    Voici comment je pensais écrire la fonction membre run() :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
     
    #include <iostream>
     
    using namespace std;
     
    template<typename L : Lifo<typename T> >
    LifoTest<L>::run() {
        /*
         * _container serait déclaré en tant que membre comme suit :
         * L _container;
         */
        if (!_container.isEmpty()) { 
            cerr << "ERROR : new LIFO container will be empty." << endl;
        }
     
        T element;
     
        cout << element << "Push to LIFO container." << endl;
        _container.push(element);
        cout << "Container size : " << _container.size();
     
        if (_container.isEmpty()) {
            cerr << "ERROR : LIFO container will not be empty after element was pushed." << endl;
        }
     
        cout << "Pop element from LIFO container." << endl;
        T popedElement = _container.pop();
        if(element != popedElement) {
            cerr << "ERROR: Poped element is different from which was pushed.";
        }
     
        if (!_container.isEmpty()) {
            cerr << "ERROR : LIFO container will be empty after last element was poped." << endl;
        }
    }
    Et comment je pensais utiliser la classe LifoTest :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
     
    int main () {
        LifoTest<BasicStack<int> > test1;
        LifoTest<ImprovedMemoryStack<float> > test2;
        LifoTest<ChainedStack<string> > test3;
     
        test1.run();
        test2.run();
        test3.run();
     
        return 0;
    }
    Ce code (qui va surement vous paraître horrible ) vient du fait qu'en Java , il est possible lors de la déclaration d'un template, de forcer le type générique (ici L) à être une classe dérivée d'une certaine classe (ici Lifo<T>).

    Laissez-moi vous expliquer la ligne de déclaration du template (qui ne fonctionne pas bien-sûr) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    template<typename L : Lifo<typename T> >
    La classe générique LifoTest accepte un paramètre template L qui doit être une classe dérivée de Lifo. Mais je ne veux pas contraindre à utiliser Lifo<int> ou Lifo<string>, donc je rajoute un second paramètre de template inclu dans le premier ("template template parameter").

  12. #12
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 629
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 629
    Points : 30 692
    Points
    30 692
    Par défaut
    Je me demande si tu n'essaye pas de mélanger trop de concepts lors de ton apprentissage...

    Le paradigme générique est bien assez complexe pour justifier de ne l'aborder qu'une fois que tu as pleinement assimilé le paradigme OO tel que mis en oeuvre avec C++

    Comme, en plus, tu viens de java, on peut craindre que tu n'arrive avec de mauvaises habitudes, voire une compréhension biaisée de certains concepts qui subissent des restrictions ou des adaptations du fait de la mentalité du langage. Et je ne parle pas seulement des termes utilisés

    Vu que tu sembles pour l'instant "patauger" avec la mise en oeuvre du paradigme OO proposée par C++, je te conseillerais volontiers de commencer par t'habituer aux seuls points qui en fassent partie: Les problèmes d'héritage (public, privé, virtuel), la problématique des fonctions membres ( classique, virtuelles, virtuelle pures) et les principes qui sont si chers aux C++istes pour s'éviter de se tirer une balle dans le pied (Demeter, LSP, délégation des tâches), et le "jargon" propre au langage (ex: fonction virtuelle pure Vs méthode abstraite ).

    Je ne dis, bien évidemment, pas qu'il faut renoncer à utiliser une collection ou un algorithme template fournit par le langage dans tes tests, mais je dis que, dans un premier temps, tu auras surement déjà bien assez de difficulté à assimiler le seul coté OO de C++ sans vouloir, en plus, aller chercher la difficulté en y rajoutant le coté générique de l'histoire

    Une fois que tu auras bien assimilé cela et que tu te sentiras à l'aise avec l'aspect OO (cela devrait malgré tout, aller assez vite ), il sera toujours bien temps de t'intéresser à l'aspect générique, et tu constatera effectivement qu'il y a moyen d'aller de surprise en surprise, mais que, si tu avais essayé d'ingurgiter cela en même temps que l'aspect OO, tu en aurais rapidement eu une indigestion

  13. #13
    Membre à l'essai
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    24
    Détails du profil
    Informations personnelles :
    Âge : 36
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 24
    Points : 18
    Points
    18
    Par défaut
    Citation Envoyé par koala01 Voir le message
    Vu que tu sembles pour l'instant "patauger" avec la mise en oeuvre du paradigme OO proposée par C++, je te conseillerais volontiers de commencer par t'habituer aux seuls points qui en fassent partie: Les problèmes d'héritage (public, privé, virtuel), la problématique des fonctions membres ( classique, virtuelles, virtuelle pures) et les principes qui sont si chers aux C++istes pour s'éviter de se tirer une balle dans le pied (Demeter, LSP, délégation des tâches), et le "jargon" propre au langage (ex: fonction virtuelle pure Vs méthode abstraite ).
    Oui, je pense que je vais suivre ton conseil et arrêter le massacre.
    Je vais me contenter de travailler avec une pile d'entiers. Ensuite, une fois que je serais bien rodé, je m'attaquerais à la généricité.

    Je passe ce sujet en délestage, parce que c'est vraiment le bordel.

    Merci !

  14. #14
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut
    Citation Envoyé par damien.flament Voir le message
    Je suis d'accord avec toi. Je pense que j'aurai dû un peu plus préciser pourquoi j'ai choisi cela.
    Pas moi. Cela n'est pas forcément absurde de définir une classe générique abstraite comme tu l'as fait au début. C'est le contrat - invariants, préconditions/postconditions - qui empêcheront une classe dérivée de faire quelque chose d'incohérent (comme une fonction de tri par exemple).

Discussions similaires

  1. Instantiation générique dans une classe paramétrée
    Par Dark_TeToN dans le forum Débuter avec Java
    Réponses: 7
    Dernier message: 07/12/2013, 09h15
  2. Réponses: 4
    Dernier message: 20/06/2013, 18h07
  3. Réponses: 2
    Dernier message: 18/04/2012, 17h47
  4. Réponses: 2
    Dernier message: 07/12/2009, 16h50
  5. membre statique dans une classe
    Par motrin dans le forum VB 6 et antérieur
    Réponses: 4
    Dernier message: 30/12/2005, 15h15

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo