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 :

Que penser des frameworks et architectures qui font dériver toutes les classes d'un SuperObjet ?


Sujet :

C++

  1. #61
    Rédacteur
    Avatar de Laurent Gomila
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    10 651
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Points : 15 920
    Points
    15 920
    Par défaut
    1- faut enregistrer la classe et ses meta data dans un singleton
    Il faut l'enregistrer oui, après le fait que ça arrive dans un singleton n'est qu'un détail interne. L'enregistrement manuel permet de ne pas avoir à passer un coup de précompilateur, mais si on préfère cette dernière option on peut toujours utiliser un précompilateur qui génère le code de création de la meta-classe. Avec Qt on n'a pas ce choix.

    2- à partir du nom ou du typeId tu peut accéder au metadata par un CAMP:Class
    Ou tout simplement à partir de l'objet. Tu sembles penser qu'il y a une différence fondamentale avec Qt, ce n'est pas le cas, c'est strictement la même chose. A partir du moment où tu transformes ton objet en sa représentation abstraite (QObject pour Qt, camp::Object pour CAMP) tu le trimballes sans avoir à connaître son type statique.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    // Avec Qt
    QObject* object = truc;
     
    // Avec CAMP
    camp::Object object = truc;
    4- il faut que l'instance encapsulée par UserObject soit du bon type pour être exploitée par CAMP:Class
    Le type est récupéré en fonction de l'objet, donc c'est forcément le bon. Seul un objet qui n'aurait pas de meta-classe provoquerait une erreur (de compilation).

    5- dans le cas d'héritage on n'accède qu'au metadata que CAMP:Class permet
    d'accéder et rien d'autre.
    C'est quoi "autre" ? Tu accèdes à tout ce que tu as enregistré pour l'objet, ni plus ni moins (y compris les infos de toutes les classes de base de l'objet).

    6-il faut un CAMP:Class compatible pour exploiter les metadata sur une instance
    C'est quoi un camp::Class "compatible" ? Tu accèdes au camp::Class que tu as enregistré pour la classe de l'objet, c'est tout.

    7- Que se passe t'il si le UserOject n'est pas compatible avec la camp::Class utilisé? Une exception? ceci est validé à la compile?
    Je ne comprends pas toutes ces histoires de compatibilité dont tu parles. Le système te donne forcément accès à la meta-classe de l'objet que tu manipules, il n'y a aucun risque d'erreur ou d'incompatibilité.

    1- les metadata sont défis directement dans la définition de la classe grâce au moc
    Ce qui est intrusif et chiant à mettre en place (MOC)

    2- les metadata sont directement accessible par l'instance
    Pareil.

    3- les metada sont hérités et on as pas besoin de connaitre le type.
    Pareil, on peut complètement s'abstraire du type une fois qu'on bosse avec les classes de CAMP.

    4- on peut ajouter des propriétés dynamiquement.
    Ce n'est pas une limitation technique, ça c'est un choix de conception qui m'a été imposé lorsque j'ai développé la bibliothèque

    Grâce au superObject, je trouve que la version Qt bien plus simple et permet des choses que ne permet pas camp( Et camp permet des choses que ne permet pas QObject). De là à dire que la version de CAMP est plus puissante ou inversement , je dit que c'est comme avec les signal/slot, c'est pas le même objectif.
    Moi je trouve au contraire que c'est exactement la même chose, d'ailleurs ça a été développé dans cet esprit.

    Bref oublions CAMP (même si pour moi c'est le meilleur exemple pour illustrer mon propos), je dis juste qu'aucune des fonctionnalités apportées par QObject ne nécessite un héritage, et tout particulièrement les meta-informations qui peuvent être obtenues via un service externe et non-intrusif aux objets. Et qui plus est sans précompilateur.

  2. #62
    yan
    yan est déconnecté
    Rédacteur
    Avatar de yan
    Homme Profil pro
    Ingénieur expert
    Inscrit en
    Mars 2004
    Messages
    10 033
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur expert
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mars 2004
    Messages : 10 033
    Points : 13 968
    Points
    13 968
    Par défaut
    Citation Envoyé par Laurent Gomila Voir le message
    Je ne comprends pas toutes ces histoires de compatibilité dont tu parles. Le système te donne forcément accès à la meta-classe de l'objet que tu manipules, il n'y a aucun risque d'erreur ou d'incompatibilité.
    J'ai peut être raté quelque chose.

    Tu as une class B héritant du class A :

    • Si camp::class est celle pour A et tu as une instance de b : camp::class te permet d'accéder au metada définie pour A et non pour B.
    • Si camp::class est celle pour B et tu as une instance de b : camp::class te permet d'accéder au metada définie pour B et non pour A.


    Tu as besoin de récupérer un camp::class compatible pour pouvoir manipuler une instance précise et donc connaitre sa nature (c'est un A, un B ou un C).

    J'ai l'impression que je pourrais avec un camp::class pour C essayer de l'appliquer sur une instance de A ou B sans que cela empêche de compiler.

    Je ne suis pas sure qu'à partir de l'instance tu peut trouver le camp::class le plus adapté
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    A * a = new B;
    const camp::Class &  metaData = "je ne sasi pas "(a);
    metaData sera celui de A ou B ??

    Ce qui est intrusif et chiant à mettre en place (MOC)
    la plupart des générateurs de makefile le font pour toi.

    Moi je trouve au contraire que c'est exactement la même chose, d'ailleurs ça a été développé dans cet esprit.
    Je te fais confiance si tu dit que c'est équivalent.
    Mais la version avec CAMP me parait beaucoup plus dure à comprendre que celle avec un superObject.

    De ce que je comprend c'est ,comme avec les signal/slopt entre boost et Qt,

    CAMP est prévue pour être statique (vérif à la compilation) alors que Qt est prévue pour être dynamique (vérif à l'exécution). Ce qui est plutôt complémentaire, l'un permet des choses que l'autre ne peut pas.

  3. #63
    Rédacteur
    Avatar de Laurent Gomila
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    10 651
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Points : 15 920
    Points
    15 920
    Par défaut
    Tu as une class B héritant du class A :

    * Si camp::class est celle pour A et tu as une instance de b : camp::class te permet d'accéder au metada définie pour A et non pour B.
    * Si camp::class est celle pour B et tu as une instance de b : camp::class te permet d'accéder au metada définie pour B et non pour A.
    La meta-classe de B ayant hérité de la meta-classe de A, dans le second cas tu auras bien accès aux meta-informations de A et de B pour ton objet b. Ici le comportement est strictement le même que celui du C++ vis-à-vis de l'héritage.

    Tu as besoin de récupérer un camp::class compatible pour pouvoir manipuler une instance précise et donc connaitre sa nature (c'est un A, un B ou un C).
    Tout comme un QObject* vient bien d'un objet dont le compilo connaît le type statique, si on remonte suffisamment loin. Là où tu commences à manipuler des QObject* pour t'abstraire du type des objets, tu peux manipuler des camp::Object. C'est pareil, l'association entre l'objet réel et sa partie abstraite est simplement faite différemment : dans Qt celle-ci est incluse dans l'objet via sa base QObject, dans CAMP elle lui est associée de manière externe à la compilation via des classes de traits.

    J'ai l'impression que je pourrais avec un camp::class pour C essayer de l'appliquer sur une instance de A ou B sans que cela empêche de compiler.
    En effet, tu pourrais et tu obtiendrais une exception. Mais ça c'est juste un détail, l'API publique permet de faire beaucoup de choses mais en utilisation normale tout est fait pour que ça n'arrive pas. D'ailleurs l'API publique nécessiterait encore quelques améliorations dans ce sens ; mais là encore, il n'y a aucun problème technique à le faire, c'est juste un arrangement des classes et fonctions qu'on fournit à l'utilisateur.

    Je ne suis pas sure qu'à partir de l'instance tu peut trouver le camp::class le plus adapté
    Si c'est possible
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    const camp::Class& derived = camp::classByObject(a); // récupère B
    la plupart des générateurs de makefile le font pour toi.
    Tout le monde ne travaille pas avec un générateur de makefile. Pour Visual Studio par exemple, il faut un plugin qui nécessite d'avoir une licence commerciale de Qt, si je ne m'abuse. Pour Code::Blocks c'est même pas en rêve je suppose, il faut passer par un makefile MinGW.

    Mais la version avec CAMP me parait beaucoup plus dure à comprendre que celle avec un superObject.
    Problème d'interface publique pas encore totalement au point, là c'est encore un peu "brut"

    Le fait est qu'on peut toujours construire sa propre abstraction par dessus ces composants de base (signaux/slots, metaclasses, ...), et que techniquement le QObject en tant que base de tout le reste est toujours inutile.

    CAMP est prévue pour être statique (vérif à la compilation) alors que Qt est prévue pour être dynamique (vérif à l'exécution). Ce qui est plutôt complémentaire, l'un permet des choses que l'autre ne peut pas.
    Les deux sont prévues pour être dynamiques. CAMP peut simplement faire quelques tests de manière statique car il utilise la meta-programmation et garde des informations de typage fort assez longtemps dans le processus interne.

  4. #64
    yan
    yan est déconnecté
    Rédacteur
    Avatar de yan
    Homme Profil pro
    Ingénieur expert
    Inscrit en
    Mars 2004
    Messages
    10 033
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur expert
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mars 2004
    Messages : 10 033
    Points : 13 968
    Points
    13 968
    Par défaut
    Merci pour les précisions.

    Donc si je met une instance dans un camp::Object, le camp::Object me donnerai accès au bon camp::Class. C'est cela?
    et je n'aurais plus besoin de faire
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    const camp::Class& metaclass = camp::classByType<MyClass>();
    Il me semble aussi que l'on peut définir plusieurs camp::Class pour une même classe, non?

  5. #65
    Rédacteur
    Avatar de Laurent Gomila
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    10 651
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Points : 15 920
    Points
    15 920
    Par défaut
    Donc si je met une instance dans un camp::Object, le camp::Object me donnerai accès au bon camp::Class. C'est cela?
    Oui. En fait idéalement camp::Object devrait fournir une interface pour manipuler l'objet directement, sans avoir à passer explicitement par la metaclasse.

    Il me semble aussi que l'on peut définir plusieurs camp::Class pour une même classe, non?
    Je ne me souviens plus pourquoi, mais oui on peut le faire

  6. #66
    yan
    yan est déconnecté
    Rédacteur
    Avatar de yan
    Homme Profil pro
    Ingénieur expert
    Inscrit en
    Mars 2004
    Messages
    10 033
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur expert
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mars 2004
    Messages : 10 033
    Points : 13 968
    Points
    13 968
    Par défaut
    Citation Envoyé par Laurent Gomila Voir le message
    Oui. En fait idéalement camp::Object devrait fournir une interface pour manipuler l'objet directement, sans avoir à passer explicitement par la metaclasse.
    D'accord, cela me parait bien totalement équivalent alors et le superObject n'est pas forcement le plus intéressant pour les metadata. Je ne pensais pas que l'on pouvais aller aussi loin

    Par contre pour le fonctionnement des signal/Slot de Qt, je pense toujours que sans le superObject se ne serait pas réellement possible. En particulier :
    * le principe d'appartenance à un thread
    * l'appel direct ou indirecte du slot suivant le cas inter/intra thread
    * les connexions dynamique

    Y as une dernière choses, ou je pense que le superObject à surement encore un intérêt. C'est la portabilité. Par exemple avec camp, y as t'il autant de compilateur supporté que Qt?
    Certains compilateurs (sauf les récents je croie) ont encore du mal avec les template, non?

  7. #67
    Rédacteur
    Avatar de Laurent Gomila
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    10 651
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Points : 15 920
    Points
    15 920
    Par défaut
    Par contre pour le fonctionnement des signal/Slot de Qt, je pense toujours que sans le superObject se ne serait pas réellement possible. En particulier :
    * le principe d'appartenance à un thread
    * l'appel direct ou indirecte du slot suivant le cas inter/intra thread
    * les connexions dynamique
    Là oui, peut-être bien qu'une classe de base commune à tous les objets qui dialoguent est la seule solution.

    Y as une dernière choses, ou je pense que le superObject à surement encore un intérêt. C'est la portabilité. Par exemple avec camp, y as t'il autant de compilateur supporté que Qt?
    Certains compilateurs (sauf les récents je croie) ont encore du mal avec les template, non?
    Oui, mais là on pourrait très bien imaginer implémenter CAMP en utilisant les mêmes techniques que Qt pour se passer de tout l'aspect meta-programmation. Le fait que le service soit fourni de manière externe ou via une classe de base n'y change pas grand chose.

  8. #68
    gl
    gl est déconnecté
    Rédacteur

    Homme Profil pro
    Inscrit en
    Juin 2002
    Messages
    2 165
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Isère (Rhône Alpes)

    Informations forums :
    Inscription : Juin 2002
    Messages : 2 165
    Points : 4 637
    Points
    4 637
    Par défaut
    Citation Envoyé par yan Voir le message
    Par contre pour le fonctionnement des signal/Slot de Qt, je pense toujours que sans le superObject se ne serait pas réellement possible. En particulier :
    * le principe d'appartenance à un thread
    * l'appel direct ou indirecte du slot suivant le cas inter/intra thread
    * les connexions dynamique
    Ce qui, de mon point de vu, ne justifie pas un super-objet, tout au plus un objet de base ayant cette unique responsabilité et dont hérite uniquement les objets ayant besoin de ce mécanisme.

  9. #69
    yan
    yan est déconnecté
    Rédacteur
    Avatar de yan
    Homme Profil pro
    Ingénieur expert
    Inscrit en
    Mars 2004
    Messages
    10 033
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur expert
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mars 2004
    Messages : 10 033
    Points : 13 968
    Points
    13 968
    Par défaut
    Citation Envoyé par gl Voir le message
    tout au plus un objet de base ayant cette unique responsabilité et dont hérite uniquement les objets ayant besoin de ce mécanisme.
    C'est ce qui se passe dans Qt, seule les classes qui ont besoin de ces système hérite directement/indirectement de QObject.
    Et en Qt c'est le superObject.

  10. #70
    Membre éclairé

    Profil pro
    Inscrit en
    Mai 2009
    Messages
    277
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2009
    Messages : 277
    Points : 742
    Points
    742
    Par défaut
    Citation Envoyé par gbdivers Voir le message
    Ce qui serait étrange, c'est que toutes tes classes dérivent directement de ton IObject
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    class MaClass : public IObject, (...)
    Par contre, qu'une classe dérive d'une classe qui dérive d'une classe qui dérive (...) qui dérive de IObject, ça ne pose pas de problème.

    Un exemple : dans Qt, la majorité des classes dérivent de QObject (pour pouvoir utiliser les meta infos, les signaux/slots, etc.)
    Oui mais pas toutes pour garder de la souplesse, contrairement à Java et C# qui (si je ne m'abuse) héritent forcément de Object.

  11. #71
    Expert éminent
    Avatar de _skip
    Homme Profil pro
    Développeur d'applications
    Inscrit en
    Novembre 2005
    Messages
    2 898
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : Suisse

    Informations professionnelles :
    Activité : Développeur d'applications
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Novembre 2005
    Messages : 2 898
    Points : 7 752
    Points
    7 752
    Par défaut
    Citation Envoyé par manudwarf Voir le message
    Oui mais pas toutes pour garder de la souplesse, contrairement à Java et C# qui (si je ne m'abuse) héritent forcément de Object.
    Non c'est juste, c'est implicite si on ne déclare rien. Toute classe est forcément un object, avec en gros en commun :

    toString()
    hashCode()
    equals()
    + un pseudo destructeur.

    Cette approche est utilisée pour les collections, les tables de hachage et assure une certaines cohérence dans le framework.

    Les frameworks de ces langages partent ainsi du principe que tout objet peut être clef d'une hashmap, toutes les méthodes de collection style remove(object) peuvent s'appuyer sur une méthode de test d'égalité et tout objet est représentable sous forme de string.

    Il faut aussi savoir que les generics ne fonctionnent pas comme les templates en C++ dans le sens ou ce n'est pas une sorte de processeur de texte (je sais que c'est réducteur).

  12. #72
    Membre confirmé
    Avatar de grishka
    Inscrit en
    Janvier 2003
    Messages
    285
    Détails du profil
    Informations forums :
    Inscription : Janvier 2003
    Messages : 285
    Points : 499
    Points
    499
    Par défaut
    Je pense qu'en général on privilégie l'héritage d'implémentation sans tenir compte des autres formes de réutilisabilité, notamment l'utilisation de la délégation et des interfaces (pour le polymorphisme) . Sans être "intégriste", l'héritage est souvent bien adapté à de petits ensembles de classe. Mais les grosses hiérarchies sont souvent difficiles à maintenir sur le long terme (A cause du fameux principe de substitution)

    certains frameworks applicatifs comme Spring ont grandement simplifiés la conception des applications. Ils permettent simplement de se passer de l'héritage (et d'autres design patterns comme le singleton, etc. ...) , en utilisant l'injection de dépendances et la configuration comme principes de base (bon ok, en simplifiant).
    "Les gens normaux croient que si ca marche, c'est qu'il n'y a rien à reparer. Les ingénieurs croient que si ca marche, c'est que ca ne fait pas encore assez de choses."
    --Scott Adams

  13. #73
    Membre du Club
    Profil pro
    Inscrit en
    Novembre 2009
    Messages
    69
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2009
    Messages : 69
    Points : 62
    Points
    62
    Par défaut
    Bonjour,
    [quote]
    Par contre pour le fonctionnement des signal/Slot de Qt, je pense toujours que sans le superObject se ne serait pas réellement possible. En particulier :
    * le principe d'appartenance à un thread
    * l'appel direct ou indirecte du slot suivant le cas inter/intra thread
    * les connexions dynamique
    Là oui, peut-être bien qu'une classe de base commune à tous les objets qui dialoguent est la seule solution.
    Je me permet de rebondir : tout ceci est complètement faisable sans héritage .
    Remarque/Solution 1 : pour implémenter de l'héritage, on fait de l'aggrégation. Donc c'est théoriquement possible de passer par de l'aggrégation.
    Solution 2 : on peut le simuler avec des templates.
    Solution 3 : on peut recopier le code sans passer par une classe de base.
    Il existe d'autres solutions, mais qui sortent un peu trop des sentiers battus pour que j'en discute ici.
    Quoiqu'il en soit, la solution 3 permet un gain de performance certain, tant au niveau de la vitesse d'exécution que de la vitesse de compilation (si je compare avec les templates).

    J'ai déjà eu l'occasion d'implémenter les versions 2 et 3. Je remarque que dans les entreprises, comme dans de nombreux projets open-source, la solution 3 est souvent négligée alors qu'elle n'est pas dénuée d'avantages.

    Le principe d'appartenance à un thread peut se traduire tout simplement par l'aggrégation d'un 'ID de thread'. Il suffit alors de comparer l'ID-thread de l'objet 'cible' exécutant le code en question avec celui du 'demandeur' pour déterminer si l'on souhaite exécuter la fonction de manière synchrone ou non (si ID1 == ID2 alors appel direct).

    A propos du SuperObject pour de l'instrospection :
    J'ai déjà implémenté un système d'introspection/réflexion en C++ utilisant la solution 3 sans difficultés. Cependant cela ne me sert qu'a faire des getters (nom attribs, nombre, taille, (de)serialization, scripting), pas de modification de type ni d'instanciation.

    SuperObject exemple de danger :
    J'ai constaté de sérieux problèmes dans un projet utilisant un SuperObject, dont l'un des premiers sous-type était un design pattern composite(!). Les problèmes étaient qu'une maison pouvait contenir une porte qui pouvait contenir une maison à nouveau etc... (ce qui est impossible) et le système ne détectait pas ces erreurs.

    Bref, de mon point de vue le SuperObject est plus dangereux qu'utile, même pour ceux qui n'ont pas de contraintes de performances.

    L'héritage est souvent bien adapté à de petits ensembles de classe
    Je partage aussi cet avis.

    Cordialement,
    El Pedro

  14. #74
    Membre éprouvé
    Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mars 2009
    Messages
    552
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Mars 2009
    Messages : 552
    Points : 1 060
    Points
    1 060
    Par défaut
    Citation Envoyé par ElPedro Voir le message
    Remarque/Solution 1 : pour implémenter de l'héritage, on fait de l'aggrégation. Donc c'est théoriquement possible de passer par de l'aggrégation.
    Solution 2 : on peut le simuler avec des templates.
    Solution 3 : on peut recopier le code sans passer par une classe de base.
    1 : Ca ne permet pas d'avoir un type unique à mettre dans un tableau par exemple.

    2 : A bas niveau, je veux bien; A haut niveau, ça revient à faire de l'héritage sans le documenter. Dans tous les cas, ça impose les mêmes contraintes sur la classe dérivée, sauf que l'on perd beaucoup d'information que l'on trouve par exemple dans des classes composées de méthodes virtuelles pure.

    3 : J'espère que c'est pas une incitation au copier/coller? Sinon, après les patterns, les anti-patterns : D.R.Y.

    SuperObject exemple de danger :
    J'ai constaté de sérieux problèmes dans un projet utilisant un SuperObject, dont l'un des premiers sous-type était un design pattern composite(!). Les problèmes étaient qu'une maison pouvait contenir une porte qui pouvait contenir une maison à nouveau etc... (ce qui est impossible) et le système ne détectait pas ces erreurs.
    C'est un exemple de mauvaise utilisation de la généricité et à la rigueur d'absence de contrôle sur les types génériques. C'est le modèle métier maison qui ne fait pas les vérifications nécessaires.
    Pas besoin de SuperObjet pour créer ce genre de problèmes. Il suffit d'un mauvais modèle.


    Bref, de mon point de vue le SuperObject est plus dangereux qu'utile, même pour ceux qui n'ont pas de contraintes de performances.
    Etendre le modèle Objet de C++ à l'aide de C++, me semble beaucoup moins dangereux que la présence de pointeur dans ce langage et l'obligation de passer par ses derniers dans certains cas de polymorphisme.

    Pour l'utilité : Aucune chance d'avoir un moteur de script tel celui de Qt sans le QObjet pour l'introspection sur les slots, signaux et propriétés. Regarde la lourdeur du code à mettre en place pour exposer une classe en javascript dans v8 de google (à base de template), par rapport à QtScript.


    L'héritage est souvent bien adapté à de petits ensembles de classe
    L'héritage est adapté aux comportements identiques point barre. Dans le cas de Qt, tout QObjet est potentiellement liés par des signaux à d'autres objets. Il n'y a pas lieux de cacher cet héritage.

    En C++, on hérite d'une table de méthode virtuelles en natif après tout. En Java, on ne se plaint pas d'avoir un si pratique Objet sous-jasent à toutes les classes, ainsi que Class qui permet d'avoir un ClassLoader. On comprend encore plus son intérêt quand on écrit une JNI et que l'on retrouve un JObjet.

    Il faut bien avoir à l'esprit ce qui fait que l'on préfère la composition à l'héritage, pour ne pas appliquer mécaniquement ce principe. Quand le SuperObjet rend les choses plus modulable et plus interchangeable; il peut apporter plus d'avantage que d'inconvénients.

    Le fait est que le modèle Objet de C++ est restreint en natif au strict nécessaire. Dès lors que l'on veut l'utiliser en plus haut niveau, que l'on veut faire communiquer ces objets, on est tenté d'étendre le modèle objet natif de C++.

    Unifier le nouveau modèle objet à travers un super-objet, plutôt que de le sous-entendre dans des templates ou autres, n'est pas à mon sens une aberration.

  15. #75
    Membre émérite
    Avatar de white_tentacle
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    1 505
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 1 505
    Points : 2 799
    Points
    2 799
    Par défaut
    Unifier le nouveau modèle objet à travers un super-objet, plutôt que de le sous-entendre dans des templates ou autres, n'est pas à mon sens une aberration.
    Relis les messages de Laurent Gomila. Il explique très bien en quoi ce n'est absolument pas une nécessité. Et à mon sens, cela apporte plus d'ennuis qu'autre chose (un SuperObjet, cela revient finalement à un typage faible, et le typage faible, c'est mal ).

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 626
    Points : 30 684
    Points
    30 684
    Par défaut
    Citation Envoyé par bretus Voir le message
    1 : Ca ne permet pas d'avoir un type unique à mettre dans un tableau par exemple.
    Normalement, tu ne devrais jamais commencer à mettre tout et n'importe quoi dans un tableau unique.

    Tu peux, bien sur, vouloir faire cohabiter certains types dans des collections, mais le nombre de type différents que tu va faire cohabiter est classiquement assez restreint:

    Tu peux envisager de faire cohabiter des avions, des motos et des camions si tu considère que ce sont des véhicules tout comme tu peux faire cohabiter des chats, des serpents et des éléphants si tu considère que ce sont des animaux.

    Mais il n'y a aucun sens à vouloir faire cohabiter des véhicules avec des animaux. Or, c'est, justement, ce que permet l'existence d'un super objet.

    Il est évident qu'il faut avoir recours aux hiérarchies de classes, c'est l'un des fondements même de l'Orienté Objet.

    Tout comme il est évident que, dés que l'on parle de hiérarchies de classes, cela implique qu'il y aura, pour chaque hiérarchie, un objet de base.

    Par contre, cela ne veut pas forcément dire que toutes les hiérarchies envisageables devront être... reliée entre elles par un super objet.
    2 : A bas niveau, je veux bien; A haut niveau, ça revient à faire de l'héritage sans le documenter.
    Absolument pas...

    L'avantage, justement, des template, c'est qu'un Type<Truc> est tout à fait indépendant d'un Type<Machin>, même si, effectivement, ils partagent la même interface.

    En simplifiant on pourrait dire que l'on pousse la réflexion sur le comportement des objets bien plus loin que ce que l'on fait généralement en OO.
    Dans tous les cas, ça impose les mêmes contraintes sur la classe dérivée, sauf que l'on perd beaucoup d'information que l'on trouve par exemple dans des classes composées de méthodes virtuelles pure.
    Cela impose certaines contraintes, en effet, mais cela apporte également une grande souplesse, et, justement, cela évite d'avoir des hiérarchies de classes plus imposantes que les pyramides d'Egypte

    Ce qu'il faut comprendre, c'est que tout n'est pas forcément adapté à tout.

    Dans certains cas, l'héritage public "classique" d'un objet ne présentant que des fonctions virtuelles pures sera la moins mauvaise solution, dans d'autres, une approche basée sur la généricité et ses techniques particulières (CRTP, type erasure, traits et politiques en tête) s'avérera bien plus avantageuse.

    Le tout sera toujours d'évaluer correctement les avantages et les inconvénients de chaque technique
    C'est un exemple de mauvaise utilisation de la généricité et à la rigueur d'absence de contrôle sur les types génériques. C'est le modèle métier maison qui ne fait pas les vérifications nécessaires.
    Pas besoin de SuperObjet pour créer ce genre de problèmes. Il suffit d'un mauvais modèle.
    C'est surement un problème de conception, mais il sera bien plus facile d'y arriver si un super objet entre dans la danse que si les hiérarchies sont clairement distinctes.
    L'héritage est adapté aux comportements identiques point barre.
    Non, il est adapté quand tu peux décemment estimer qu'il y a une relation EST-UN entre deux objets selon la granularité que tu envisages...
    En C++, on hérite d'une table de méthode virtuelles en natif après tout.
    Non, justement...

    A la différence de Java, il n'y a une table de méthodes virtuelles que (et uniquement) s'il existe une fonction virtuelle dans la classe.

    Or, si tu pars, à la base, sur l'idée d'un super objet dont héritent (de manière directe ou indirecte) toutes tes classes, tu force à l'existence de cette table virtuelle quasi à tous les coups (car il y a de fortes chances qu'un certain nombre de fonctions de ce super objet soient virtuelles)
    Il faut bien avoir à l'esprit ce qui fait que l'on préfère la composition à l'héritage, pour ne pas appliquer mécaniquement ce principe.
    Non...

    Quand on préfère la composition à l'héritage, c'est parce que l'on a compris que l'héritage est la relation la plus forte qui puisse exister entre deux objets, et que la composition est une relation bien plus souple.

    C'est pour cette raison que l'on conseille généralement de préférer la composition à l'héritage à moins que l'on ait de bonnes raison de recourir à ce dernier
    Quand le SuperObjet rend les choses plus modulable et plus interchangeable; il peut apporter plus d'avantage que d'inconvénients.
    Le fait est que, s'il rend (parfois à tord) les choses plus interchangeables, il ne rend pas forcément (je dirais même "bien au contraire") les choses plus modulables.

    Et dans biens des cas, cet aspect "d'interchangeabilité" excessive devient rapidement un source de problèmes sans noms.
    Le fait est que le modèle Objet de C++ est restreint en natif au strict nécessaire.
    C'est un fait... largement compensé par l'existance d'autres paradigmes fournis par le langage.
    Dès lors que l'on veut l'utiliser en plus haut niveau, que l'on veut faire communiquer ces objets, on est tenté d'étendre le modèle objet natif de C++.
    Souvent à tord, car il est malgré tout rare que n'importe quel objet puisse envoyer n'importe quel message à n'importe quel autre objet.

    Le plus souvent, un objet donné ne pourra envoyer qu'un certain type de message à une certain nombre d'objet et ne pourra (dans l'autre sens) recevoir qu'un certain type de message d'un ensemble d'objets clairement défini.
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  17. #77
    yan
    yan est déconnecté
    Rédacteur
    Avatar de yan
    Homme Profil pro
    Ingénieur expert
    Inscrit en
    Mars 2004
    Messages
    10 033
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur expert
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mars 2004
    Messages : 10 033
    Points : 13 968
    Points
    13 968
    Par défaut
    Quand on préfère la composition à l'héritage, c'est parce que l'on a compris que l'héritage est la relation la plus forte qui puisse exister entre deux objets, et que la composition est une relation bien plus souple.

    C'est pour cette raison que l'on conseille généralement de préférer la composition à l'héritage à moins que l'on ait de bonnes raison de recourir à ce dernier
    dit comme cela ça fait peur, ça donne l'impression qu'il faut éviter l'héritage...

    La agrégation limite quand même pas mal de chose. Par exemple, par rapport à
    Le principe d'appartenance à un thread peut se traduire tout simplement par l'aggrégation d'un 'ID de thread'. Il suffit alors de comparer l'ID-thread de l'objet 'cible' exécutant le code en question avec celui du 'demandeur' pour déterminer si l'on souhaite exécuter la fonction de manière synchrone ou non (si ID1 == ID2 alors appel direct).
    il faut
    1- que chaque classe est un ID
    2- pouvoir tester n'importe quel ID d'une classe avec n'importe quel id d'une autre classe.

    Par agrégation : faut connaitre toute les classes qui ont un Id pour permettre cela. Y as surement une solution à base de template, mais ça deviens franchement le bordel, et si une instance proviens d'un plug-in, on pourra plus faire ce teste.

    Avec la classe parent : y as plus rien à faire.

    Et encore je parle même pas comment faire un appel synchrone et asynchrone...

    L'agrégation t'oblige à connaitre l'environnement alors que le SuperObject te l'interface.

    Après c'est comme tous, tous dépend du l'objectif et des contraintes.

    Le super object permet quand même de simplifier (voire rend possible) les choses. C'est une brique qui te permet d'exploiter tes classes dans une architecture de manière dynamique et souple.


    Solution 3 : on peut recopier le code sans passer par une classe de base.
    Ca ça me fait vraiment peur.. Que veut tu dire par là?

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 626
    Points : 30 684
    Points
    30 684
    Par défaut
    Je ne répondrai qu'à la partie qui me concerne...
    Citation Envoyé par yan Voir le message
    dit comme cela ça fait peur, ça donne l'impression qu'il faut éviter l'héritage...
    C'est effectivement le cas, dans le sens où il faut s'assurer que l'héritage ait un sens (que la sémantique de la classe dérivée soit bien compatible avec une relation EST-UN par rapport à la classe de base) et que l'on utilise la granularité correcte par rapport au contexte.

    On pourra bien sur estimer en toutes circonstances qu'une tasse, une porte, une voiture ou un morceau de sucre sont des objets mais on y applique alors une granularité tellement fine que l'on perd la possibilité de les utiliser d'une quelconque manière, parce que tous les comportements que l'on pourrait envisager au départ de Objet (quelle que soit l'orthographe utilisée) sont beaucoup trop génériques et nous oblige à tester au minimum si un objet (dont on ignore tout) est effectivement du type d'une des classes intermédiaire.

    Tu ne peux en effet pas prévoir, dans l'interface de Objet l'ensemble des comportements potentiels de chacun des types envisager, ne serait-ce que parce qu'il n'y a aucun sens à vouloir essayer de démarrer un morceau de sucre
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  19. #79
    yan
    yan est déconnecté
    Rédacteur
    Avatar de yan
    Homme Profil pro
    Ingénieur expert
    Inscrit en
    Mars 2004
    Messages
    10 033
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur expert
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mars 2004
    Messages : 10 033
    Points : 13 968
    Points
    13 968
    Par défaut
    On est d'accord. Merci pour la précision

    Citation Envoyé par koala01 Voir le message
    Tu ne peux en effet pas prévoir, dans l'interface de Objet l'ensemble des comportements potentiels de chacun des types envisager, ne serait-ce que parce qu'il n'y a aucun sens à vouloir essayer de démarrer un morceau de sucre
    En Qt, QObject n'est là que pour fournir une base de fonctionnalités liées à son architecture. Il ne fait aucune hypothèse sur la nature de la classe finale (contrairement à QWidget qui spécialise pour la partie IHM). Et pour moi, c'est grâce à cela que Qt simplifie son exploitation et trouve toutes sa puissance (fonctionnement dynamique). Une fois que tu à compris QObject, tu comprend comment fonctionne Qt. Sans ce superObject je pense qu'il est trés simple d'avoir un ensemble de classe avec une philosophie et un autre totalement opposé. A moins de connaitre toutes les subtilités de chaque classes, ca deviens


    Là où le super object pose les règles, son absence ouvre la porte vers un chaos potentiel.

    Ca ne veut pas dire qu'il en faut un tout le temps, bien au contraire. Et ceci résume bien
    Citation Envoyé par koala01 Voir le message
    C'est effectivement le cas, dans le sens où il faut s'assurer que l'héritage ait un sens (que la sémantique de la classe dérivée soit bien compatible avec une relation EST-UN par rapport à la classe de base) et que l'on utilise la granularité correcte par rapport au contexte.

  20. #80
    Membre éprouvé
    Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mars 2009
    Messages
    552
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Mars 2009
    Messages : 552
    Points : 1 060
    Points
    1 060
    Par défaut
    Bonsoir,

    D'abord, merci à tous d'avoir précisé certains points et d'en avoir corrigé d'autres.

    koala01, je vais méditer certains points de ton post. J'avoue que je n'ai pas une opinion très fixe sur le sujet.

    Tu peux envisager de faire cohabiter des avions, des motos et des camions si tu considère que ce sont des véhicules tout comme tu peux faire cohabiter des chats, des serpents et des éléphants si tu considère que ce sont des animaux.

    Mais il n'y a aucun sens à vouloir faire cohabiter des véhicules avec des animaux. Or, c'est, justement, ce que permet l'existence d'un super objet.
    Qt unifie au sein de QObjet, où QObjet EST-UN "objet au sens de Qt", appartenant à une hiérarchie de classe arborescente, muni d'un mécanisme de signaux, attaché à un thread...

    Un SIGiste travaille sur un objets géographiques (pont fleuve, rivière) muni de données attributaires, d'une géométrie, de relations topologiques avec d'autres objets ( là en template )

    Pour ton exemple, du point de vue du concepteur de moteur de rendu 3D? Du moins, pour ce qu'il a besoin d'en faire : Les avions, les motos, les chats, les véhicules SONT DES DynamicObject?

    Ce qu'il faut comprendre, c'est que tout n'est pas forcément adapté à tout.
    Voilà qui résume bien le pourquoi du on va tous s'entretuer sur les cas intermédiaires où ni l'un ni l'autre ne sont mieux, mais juste question de goût .


    Pour ma part, je suis persuadé du fait que l'architecture des classes dépend des besoins au sens où un objet complexe doit être présenté sous différentes interfaces... C'est un peu ce qui me chagrine dans le Mapping brutal des modèles UML de données métiers (conceptuel) sur les classes "effectives".

    Ce n'est pas en créant la classe ObjetGeographique que l'on forme un tout innommable et que l'on se tire une balle dans le pied; c'est en travaillant trop souvent avec les classes concrètes Pont, Ville, Chateau, sans jamais avoir besoin leurs spécificités; et ce sans jamais avoir extrait l'interface "ObjetGeographique" : données attributaires + géométrie...

    Alors, qu'il s'agisse de ObjetGeographique ou T_OG : Qu'importe dans le fond, ça reste des spécifications sur lesquelles il ne faut pas se vautrer, car on aura bien du mal à revenir sur sa conception...

    Bonne soirée

Discussions similaires

  1. Réponses: 36
    Dernier message: 12/01/2011, 15h55
  2. Que penser des testeurs de Carte Mère
    Par Fabdeuche dans le forum Ordinateurs
    Réponses: 1
    Dernier message: 26/11/2010, 10h35
  3. Réponses: 0
    Dernier message: 15/11/2010, 11h51
  4. Un programme qui lance quelquechose toute les 50 minutes?
    Par altadeos dans le forum C++Builder
    Réponses: 4
    Dernier message: 12/03/2006, 11h16

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