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

C++ Discussion :

[Downcasting] Violation de Principes Orienté Objet ?


Sujet :

C++

  1. #1
    Membre Expert
    Avatar de poukill
    Profil pro
    Inscrit en
    Février 2006
    Messages
    2 155
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France

    Informations forums :
    Inscription : Février 2006
    Messages : 2 155
    Par défaut [Downcasting] Violation de Principes Orienté Objet ?
    Bonjour à tous,

    Je possède une classe de base assez conséquente (appelons là Base) et une multitude de classes filles (Fille1, Fille2, Fille3, Fille4) qui implémentent les fonctions virtuelles de Base via un template method.
    Seulement, chaque classe fille a son petit truc à soi, comme ActivateFonction1(), etc...

    Ainsi, dans mes fenêtres WxWidget qui possèdent une Base*, je suis obligé à chaque fois de downcaster pour pouvoir me servir des petits trucs de chaque Fille.

    Vous en pensez quoi ? Mauvaise conception ou phénomène inéluctable ?

  2. #2
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 398
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 398
    Par défaut
    Si c'est du downcasting dynamique, je pense c'est possible que ce soit une mauvaise conception.
    Si c'est statique, il est probable selon moi que ce soit un phénomène inéluctable.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  3. #3
    Membre éclairé Avatar de befalimpertinent
    Profil pro
    Inscrit en
    Avril 2007
    Messages
    561
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France, Gironde (Aquitaine)

    Informations forums :
    Inscription : Avril 2007
    Messages : 561
    Par défaut
    C'est vrai que ça sent le problème de conception à plein nez !
    N y a t'il vraiment aucun moyen d'utiliser le polymorphisme pour l'appel de tes fonctions ActivateFonction1(), ... ?

  4. #4
    Membre Expert
    Avatar de poukill
    Profil pro
    Inscrit en
    Février 2006
    Messages
    2 155
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France

    Informations forums :
    Inscription : Février 2006
    Messages : 2 155
    Par défaut
    Citation Envoyé par Médinoc Voir le message
    Si c'est du downcasting dynamique, je pense c'est possible que ce soit une mauvaise conception.
    Si c'est statique, il est probable selon moi que ce soit un phénomène inéluctable.
    C'est du statique, car je suis sûr du downcasting...

    Citation Envoyé par befalimpertinent Voir le message
    C'est vrai que ça sent le problème de conception à plein nez !
    N y a t'il vraiment aucun moyen d'utiliser le polymorphisme pour l'appel de tes fonctions ActivateFonction1(), ... ?
    Si, de mettre ActivateFonction1() dans la classe mère, mais ça n'a aucun sens pour les autres classes Filles... Résultat : effet de bord global pour une modification locale...

    En fait si, il y aurait une solution à base du pattern Stratégie peut-être. C'est à dire encapsuler ce qui varie avec la composition. J'aurai un comportement ne rien faire si j'appelle la fonction ActivateFiltrage() par exemple, ou bien un comportement de filtrage.
    Mais bon ça fait un peu "forcer" la conception à rentrer dans un moule pour éviter de downcaster... C'est pas forcément très propre non plus...

    Mon problème est un problème général en fait : comment fait t-on pour manipuler un objet qui implémente des fonctions membres qui lui sont propres en plus de l'interface de la classe de base ?
    Réponse : on peut pas sans downcaster...

    Je vais continuer à creuser ma conception pour essayer de contourner ce problème ...

  5. #5
    Expert confirmé

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Par défaut
    A chaque fois que j'ai pense que le downcasting etait une bonne solution, les evolutions ulterieures m'ont montre que ce que je voulais en fait etait du dispatch multiple. Ta description est trop vague pour en etre sur, mais j'envisagerais la chose. La technique habituelle pour implementer du dispatch multiple en C++ est generalement expliquee en conjonction avec le pattern visiteur.

  6. #6
    Membre Expert
    Avatar de poukill
    Profil pro
    Inscrit en
    Février 2006
    Messages
    2 155
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France

    Informations forums :
    Inscription : Février 2006
    Messages : 2 155
    Par défaut
    Je connaissais pas le dispatch multiple, je suis en train de bosser dessus, j'ai trouvé ICI des choses intéressantes. Je suis preneur de toutes autres infos...

    @ Jean-Marc : Il y a quand même des cas où le downcasting est obligatoire non ? Où on est obligé de connaitre exactement le type manipulé ?

  7. #7
    Membre Expert

    Profil pro
    Inscrit en
    Juin 2006
    Messages
    1 294
    Détails du profil
    Informations personnelles :
    Localisation : Royaume-Uni

    Informations forums :
    Inscription : Juin 2006
    Messages : 1 294
    Par défaut
    Salut,

    Qu'est-ce qui déclenche un appel aux méthodes spécifiques des classes filles ?
    Est-ce que cette prise de décision ne pourrait pas être encapsulée dans une abstraction de plus haut niveau qui n'aurait justement pas connaissance de l'existence des spécificités des classes filles ?
    Je pense par exemple peut-être tout simplement à une méthode virtuelle DoPreSomething() qui serait appelée quelque part avant le DoSomething() de ton template method.
    Ensuite il faudrait encapsuler tout ce qui concerne ActivateFunction1() (le test pour savoir si faut l'appeler et toutes les données nécessaires pour ça) dans l'implémentation de DoPreSomething() pour Fille1.

    En résumé à mon avis il manque peut-être un niveau d'abstraction.
    (et sans doute une factorisation dans Base de données qui devraient être laissées dans les classes filles pour pouvoir y encapsuler les traitements spécifiques, mais là sans plus d'informations c'est de la boule de crystal )

    MAT.

  8. #8
    Expert confirmé

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Par défaut
    Citation Envoyé par poukill Voir le message
    @ Jean-Marc : Il y a quand même des cas où le downcasting est obligatoire non ? Où on est obligé de connaitre exactement le type manipulé ?
    D'une part, les preuves d'inexistance sont particulierement difficile a faire, c'est pour cela que j'ai qualifie en parlant de mon experience. J'ai du mal a savoir a quel point elle se generalise Surtout que meme si ce dont on a besoin, c'est du dispatch multiple, les problemes d'implementation peuvent inciter a preferer une solution a base de downcasting. C'est lie a une problematique bien connue.

  9. #9
    Membre Expert
    Avatar de poukill
    Profil pro
    Inscrit en
    Février 2006
    Messages
    2 155
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France

    Informations forums :
    Inscription : Février 2006
    Messages : 2 155
    Par défaut
    Citation Envoyé par Mat007 Voir le message
    En résumé à mon avis il manque peut-être un niveau d'abstraction.
    (et sans doute une factorisation dans Base de données qui devraient être laissées dans les classes filles pour pouvoir y encapsuler les traitements spécifiques, mais là sans plus d'informations c'est de la boule de crystal )
    Hum... ça m'intéresse d'avoir ton avis, j'ai peut-être raté quelque chose.
    OK je voulais essayer de faire comprendre le problème sans trop exposer mes vrais classes (c'est toujours plus difficile à comprendre pour les autres) mais bon j'y vais.

    J'ai une classe de base abstraite Camera, simple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    class Camera {
    public:
        // constructeur  + destructeur + méthodes communes à toutes les caméras
        Image  LoadImage (int numero) {return m_Image; }
     
    protected:
        virtual void ImportImage (int numero) = 0; // A implémenter dans les classes filles
        Image m_Image; //Stocke la dernière image importée
    };
    Comme je gère plein de caméras différentes, avec plein de façon différentes de récupérer les données, j'encapsule le rapatriement des images depuis un endroit donné dans ImportImage().

    Les caméras sont nombreuses : CameraVisible, CameraInfraRouge, etc...
    Seulement certaines d'entre elles sont un tout petit peut différente, elles se voient appliquer un filtre, et il faut donc multiplier l'image par un facteur global à calculer. D'autres calculs aussi. Ce qui nous donne :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    class CameraVisible : public Camera {
    public:
        // constructeurs etc...
        void SetFilterOn();
        void SetFilterOff();
     
        void SetFluxOn();
        void SetFluxOff();
     
    protected:
        virtual void ImportImage (int ); //implémenté dans le .cpp
    };
    Un exemple de mon programme pourrait être celui-ci : j'ai 6 fenêtres windows possédant chacune un pointeur vers une Camera.
    • S'il agit d'une CameraVisible, la fenêtre doit laisser la possibilité dans les menus déroulants d'actionner SetFilterOn()
    • S'il agit d'une Camera "normale", alors ces menus sont grisés pour montrer que cette opération n'est pas disponible...


    Je pense avoir ici bien illustré mon problème... J'espère que vous aurez beaucoup de critiques et de solutions à proposer, j'adore apprendre...


  10. #10
    Membre Expert

    Profil pro
    Inscrit en
    Juin 2006
    Messages
    1 294
    Détails du profil
    Informations personnelles :
    Localisation : Royaume-Uni

    Informations forums :
    Inscription : Juin 2006
    Messages : 1 294
    Par défaut
    Si tu as peu d'opérations particulières tu peux éventuellement les remonter sur l'interface/classe de base (SetFilterOn() par exemple ne fera rien quand une caméra n'a pas de filtre).
    Il faut sans doute ajouter des accesseurs un peu moches pour gérer les entrées dans le menu (genre un splendide bool HasFilter() const) ou bien préciser au moment de l'enregistrement d'une caméra auprès de la fenêtre quelles opérations elle supporte.

    Par contre si tu as beaucoup d'opérations différentes et/ou que tu penses devoir en rajouter en rajoutant des nouvelles implémentations de caméras (et que ça risque d'arriver assez souvent) ça serait plus pratique de les délocaliser dans un visiteur.

    Citation Envoyé par GoF
    Use the Visitor pattern when

    * an object structure contains many classes of objects with differing interfaces, and you want to perform operations on these objects that depend on their concrete classes.

    * many distinct and unrelated operations need to be performed on objects in an object structure, and you want to avoid "polluting" their classes with these operations. Visitor lets you keep related operations together by defining them in one class. When the object structure is shared by many applications, use Visitor to put operations in just those applications that need them.

    * the classes defining the object structure rarely change, but you often want to define new operations over the structure. Changing the object structure classes requires redefining the interface to all visitors, which is potentially costly. If the object structure classes change often, then it's probably better to define the operations in those classes.
    MAT.
    (comme quoi ma boule de crystal ne fonctionne pas du tout... )

  11. #11
    Membre Expert
    Avatar de poukill
    Profil pro
    Inscrit en
    Février 2006
    Messages
    2 155
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France

    Informations forums :
    Inscription : Février 2006
    Messages : 2 155
    Par défaut
    Ah la boule de cristal ne permet pas toujours tout !

    Ok vraiment je pense que je suis dans la bonne direction. Le pattern Visiteur est très certainement une grosse partie de ma solution.

    Je propose donc de mettre dans l'interface Camera une classe State pour représenter l'état de la caméra : filtre activé ou pas... etc...

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    class Camera {
    public:
        // constructeur  + destructeur + méthodes communes à toutes les caméras
        Image  LoadImage (int numero) {return m_Image; }
     
    protected:
        virtual void ImportImage (int numero) = 0; // A implémenter dans les classes filles
        Image m_Image; //Stocke la dernière image importée
        State m_State;
    };
    avec
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    struct State {
        bool m_Filter;
        bool m_Flux;
        //etc...
    };
    Et voici le visiteur, assez simple:
    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
    struct Visitor {
        virtual void Visit (Camera *) = 0;
    };
     
    class CameraStateVisitor : public Visitor {
    public:
        virtual void Visit(Camera * cam) { cam->GetState(); }
     
        // Fonctions pour récupérer les états
        void HasFilter() const {return m_State.m_Filter;}
        void HasFlux()  const {return m_State.m_Flux;}
     
    private:
        State m_State;
    };
    Mais bon, tout compte fait je me demande presque si ce serait pas plus simple pour le client d'appeler directement la méthode GetState() de l'interface Camera...

    Ton avis là dessus Mat ? Je suis dans la bonne direction? OU alors j'ai tout faux ?

  12. #12
    Membre Expert

    Profil pro
    Inscrit en
    Juin 2006
    Messages
    1 294
    Détails du profil
    Informations personnelles :
    Localisation : Royaume-Uni

    Informations forums :
    Inscription : Juin 2006
    Messages : 1 294
    Par défaut
    Pour utiliser un visiteur il faudrait plus faire quelque chose comme :
    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
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    class CameraVisitor
    {
        ...
    public:
        virtual void Visit( CameraVisible& camera ) = 0;
        virtual void Visit( CameraInfraRouge& camera ) = 0;
        virtual void Visit( CameraInMashedPotatoes& camera ) = 0;
        ...
    };
     
    class Menu
    {
        ...
    public:
        virtual void RegisterFilter( boost::function< void() > f ) = 0;
        virtual void RegisterFlux( boost::function< void() > f ) = 0;
    };
     
    class MenuCameraVisitor : private CameraVisitor
    {
    public:
        explicit MenuCameraVisitor( Menu& menu )
          : menu_( menu )
        {
            // NOTHING
        }
    private:
        virtual void Visit( CameraVisible& camera )
        {
            menu_.RegisterFilter( boost::bind( &CameraVisible::SetFilterOn, boost::ref( camera ) ) );
        }
        virtual void Visit( CameraInfraRouge& camera )
        {
            menu_.RegisterFlux( boost::bind( &CameraVisible::SetFluxOn, boost::ref( camera ) ) );
        }
        virtual void Visit( CameraInMashedPotatoes& /*camera*/ )
        {
            // NOTHING
        }
    private:
        Menu& menu_;
    };
     
    class CameraVisible : public Camera
    {
        ...
    public:
        void Accept( CameraVisitor& visitor )
        {
            visitor.Visit( *this );
        }
    };
    (fait viteuf, avec du boost::function pour la fonction réflexe, mais c'est l'idée)
    On voit bien que du coup ça alourdit quand même pas mal. C'est à mettre en balance avec la solution plus simple d'ajouter tout ce qu'il faut directement sur l'interface, du style :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    class Camera
    {
        ...
    public:
        virtual void SetFilterOn() = 0;
        virtual void SetFluxOn() = 0;
     
        virtual bool SupportsFilter() = 0;
        virtual bool SupportsFlux() = 0;
    };
    Si les opérations possibles sont fixes et en nombre pas très élevé (et tu penses rajouter plein de caméras sans ajouter d'opérations dans l'avenir) alors ça suffit peut-être.

    MAT.
    edit : typo

  13. #13
    Membre Expert
    Avatar de poukill
    Profil pro
    Inscrit en
    Février 2006
    Messages
    2 155
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France

    Informations forums :
    Inscription : Février 2006
    Messages : 2 155
    Par défaut
    Ok MAT, ta solution est très intéressante.
    Ton exemple ci dessus me permet effectivement de gérer la barre d'outils spécifiques à chaque caméra.

    Par contre, le vrai problème est :
    1. Pour chaque fonction spécifique à chaque caméra, je devrai avoir un nouveau visiteur.
    2. Pour chaque nouvelle Caméra, il faut redéfinir tous les visiteurs !


    Il n'y aurai pas moyen de laisser un comportement par défaut à l'aide de template + surchage ?

  14. #14
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 398
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 398
    Par défaut
    Pas à ma connaissance.
    On ne peut avoir de fonction virtuelle template (enfin, "plus template que la classe") en C++...
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  15. #15
    Membre Expert
    Avatar de poukill
    Profil pro
    Inscrit en
    Février 2006
    Messages
    2 155
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France

    Informations forums :
    Inscription : Février 2006
    Messages : 2 155
    Par défaut
    Oui je sais qu'une fonction virtuelle ne peut pas être template, je cherche juste à mettre un comportement par défaut à mon visiteur. Mais à bien y réfléchir cela ne me semble pas possible ...

  16. #16
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 398
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 398
    Par défaut
    Tu peux toujours faire hériter tes visiteurs d'une classe abstraite et non seulement d'une "interface". Ainsi, si tu ajoutes un type de visité, tu pourras donner un comportement par défaut à ta classe abstraite si tu ne redéfinis pas chaque visiteur...
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  17. #17
    Membre Expert

    Profil pro
    Inscrit en
    Juin 2006
    Messages
    1 294
    Détails du profil
    Informations personnelles :
    Localisation : Royaume-Uni

    Informations forums :
    Inscription : Juin 2006
    Messages : 1 294
    Par défaut
    Citation Envoyé par poukill Voir le message
    Pour chaque fonction spécifique à chaque caméra, je devrais avoir un nouveau visiteur
    Si certaines caméras peuvent cumuler plusieurs fonctions (filtre + flux dans l'exemple), effectivement il va falloir un visiteur par fonction.
    Tu as combien de fonctions en gros ?

    Citation Envoyé par poukill Voir le message
    Pour chaque nouvelle Caméra, il faut redéfinir tous les visiteurs ! Il n'y aurai pas moyen de laisser un comportement par défaut à l'aide de template + surchage ?
    Tu peux définir ton visiteur comme ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    class CameraVisitor
    {
        ...
    public:
        virtual void Visit( CameraVisible& /*camera*/ ) {}
        virtual void Visit( CameraInfraRouge& /*camera*/ ) {}
        ...
    };
    Ou alors j'ai pas bien compris ce qui te pose problème ?

    MAT.

  18. #18
    Membre Expert
    Avatar de poukill
    Profil pro
    Inscrit en
    Février 2006
    Messages
    2 155
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France

    Informations forums :
    Inscription : Février 2006
    Messages : 2 155
    Par défaut
    Citation Envoyé par Mat007 Voir le message
    Si certaines caméras peuvent cumuler plusieurs fonctions (filtre + flux dans l'exemple), effectivement il va falloir un visiteur par fonction.
    Tu as combien de fonctions en gros ?
    De 0 à 10 par Caméra en gros.

    Tu peux définir ton visiteur comme ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    class CameraVisitor
    {
        ...
    public:
        virtual void Visit( CameraVisible& /*camera*/ ) {}
        virtual void Visit( CameraInfraRouge& /*camera*/ ) {}
        ...
    };
    Ou alors j'ai pas bien compris ce qui te pose problème ?
    Oui c'est ça...

    En tout cas ça marche très bien sur le papier, je vais voir comment je peux intégrer tout ça !


  19. #19
    Membre émérite Avatar de HanLee
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    738
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Rhône (Rhône Alpes)

    Informations forums :
    Inscription : Mai 2004
    Messages : 738
    Par défaut
    Ca marche aussi en mettant le type des arguments comme templates.

    Et sinon ce mécanisme de visiteur est utilisé dans boost::variant, pour simuler les types variant (types somme) qui existent dans les langages fonctionnels, comme OCaml par exemple. Tu devrais peut-être jeter un coup d'oeil.

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

Discussions similaires

  1. Définitions de programmation impérative et orientée objet
    Par sjrd dans le forum Langages de programmation
    Réponses: 10
    Dernier message: 10/09/2005, 19h32
  2. Stack OverFlow ou Violation d'adresse - Orienté Objet
    Par JakeGrafton dans le forum Langage
    Réponses: 7
    Dernier message: 31/05/2005, 16h34
  3. [DEBUTANT] Conseil sur la programmation orienté objet
    Par etiennegaloup dans le forum Langage
    Réponses: 7
    Dernier message: 27/05/2005, 12h59
  4. Réponses: 2
    Dernier message: 01/05/2005, 14h43
  5. [SGBDOO] Base de données orientée objet
    Par Jaona dans le forum Décisions SGBD
    Réponses: 19
    Dernier message: 14/04/2003, 11h07

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