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 :

Pas de conversion implicite Objet => Objet& ? | Vtable obligatoire?


Sujet :

Langage C++

  1. #21
    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
    Par défaut
    Salut,
    J'ai repris la discussion depuis le début.
    Citation Envoyé par Zenol Voir le message
    (Ma classe mère = Un objet dans l'espace, concepts abstrait. Classe fille : Un objet particulier dans l'espace, comme un chien, une voiture, une bouche d'incendie... Quelque chose qui existe et se comporte, et bien sur a une position.)
    Je suis embêté par cette phrase qui me fait plus penser à une relation classe/instance qu'à une relation classe de base/classe dérivée.

    Citation Envoyé par Zenol Voir le message
    Ma classe mère définie ce qu'est et ce que doit avoir toute classe fille, qui implémente ses méthodes.
    Citation Envoyé par Zenol Voir le message
    Puis après tout dans le fond, si l'on fait une liste d'objet localisable, on peu certes les mélanger et utiliser leurs méthodes... Mais ca n'a aucun sens.
    Citation Envoyé par Zenol Voir le message
    Mélanger les trois dans une liste ne veux rien dire... Pourtant tous peuvent être positionner de la même façon, et ca évite une horrible redondance de code.)
    Ces 3 phrases me font poser une question :
    Quel code souhaites-tu factoriser ?
    1/ Celui qui est implémenté dans tes classes 'concepts' (par expl, Localisable) ? Auquel cas, c'est bien un héritage privé que tu dois faire pour que les classes dérivées bénéficient de l'implémentation de la classe de base. Les méthodes virtuelles te servent alors pour jouer avec les points de variation de la classe de base.
    Les méthodes publiques ont une portée privée lors d'un héritage privée.

    2/ Souhaites tu factoriser le code qui manipule tes objets ? C'est pour cela que tu veux leur imposer de dériver de Localisable ?
    Auquel cas, tu n'as peut être même pas besoin d'héritage.
    Si la seule chose que doit partager Light et Camera, c'est g/setPosition parceque tu as une fonction Move qui déplace tes objets, alors c'est Move qui devrait être générique :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    template<class Movable>
    void Move(Movable &obj_, Vecteur translation_)
    {
       Vecteur pos = obj_.getPosition();
       obj_.setPosition(pos+translation_);
       // ou la version Koala :
       obj_.Move(translation_);
    }
    Rien à rajouter dans Light ou Camera. Tu auras une erreur de compilation s'ils n'ont pas de fonctions g/setPosition.
    S'il s'agit bien de ce cas, j'ai l'impression que tu as voulu par l'héritage imposer des 'concepts' à tes classes concrètes (Light/Camera/etc.). Normalement, tu n'as pas à agir sur ces classes. Laisses les fonctions génériques échouées à la compilation si elles sont instanciées avec des classes n'ayant pas la bonne interface. Tu peux utiliser Boost.Concept Check pour documenter (et faciliter la détection des erreurs) sur les concepts sur lesquels s'appuient une fonction/class générique.

    Tu peux te servir des classes traits et des classes politiques pour construire tes fonctions génériques :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    template<class Movable>
    void Move(Movable &obj_, Vecteur translation_)
    {
    typedef movable_trait<Movable> t_trait;
    typedef movable_policy<Movable> t_policy;
       t_trait::position_type pos = t_policy::get_position(obj_);
       pos +=translation_;
       t_policy::set_position(obj_,pos);
    }
    Puis après :
    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
     
    template<class T>
    struct movable_policy
    {
    typedef movable_trait<T> t_trait;
      static t_trait::position_type get_position(T const&obj_)
      { return obj_.get_position();}
    }
     
    template<>
    struct movable_policy<SpotLigth>
    {
    typedef movable_trait<T> t_trait;
      static t_trait::position_type get_position(T const&obj_)
      { return obj_.orgine();}
    }
     
    template<>
    struct movable_policy<Nuage>
    {
    typedef movable_trait<T> t_trait;
      static t_trait::position_type get_position(T const&obj_)
      { return obj_.barycentre();}
    }
    Je crois que tu as déjà lu l'excellent article de Alp sur les traits et les politiques.

  2. #22
    Membre éclairé
    Avatar de Zenol
    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2004
    Messages
    812
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2004
    Messages : 812
    Par défaut
    Citation Envoyé par 3DArchi Voir le message
    Salut,
    J'ai repris la discussion depuis le début.

    Je suis embêté par cette phrase qui me fait plus penser à une relation classe/instance qu'à une relation classe de base/classe dérivée.


    Ces 3 phrases me font poser une question :
    Quel code souhaites-tu factoriser ?
    1/ Celui qui est implémenté dans tes classes 'concepts' (par expl, Localisable) ? Auquel cas, c'est bien un héritage privé que tu dois faire pour que les classes dérivées bénéficient de l'implémentation de la classe de base. Les méthodes virtuelles te servent alors pour jouer avec les points de variation de la classe de base.
    Les méthodes publiques ont une portée privée lors d'un héritage privée.
    Cette dernière phrase est le problème.
    Je ne veut pas que Objet::getPosition soit priver...

    Citation Envoyé par 3DArchi Voir le message
    2/ Souhaites tu factoriser le code qui manipule tes objets ?
    En fait, non... C'est Koala01 qui souhaite à tout prix que mes objets se déplace, sauf qu'ils ne se déplacent pas. (Et ne se déplaceront pas).
    Le code qui manipule un objet, c'est le code de l'utilisateur (Ici je code plus une Lib qu'un programme enfaite.)
    Il est bien question de créer une classe capable de charger une scène depuis un fichier de description/d'écrire une scène dans un fichier, mais c'est une autre histoire dont il ne seras pas question avant un certain temps.

    Je crois que je n'arrive pas a m'exprimer clairement, peut-être quelques lignes de code seront plus claire ?
    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
    class Positionable
    	{
    	public:
    		/// Access object position
    		Position &getPosition();
     
    		/// Acess object position (read only)
    		const Position &getPosition() const;
     
    		/// Replace position
    		void setPosition(const Position &pos);
     
    		/// Change position
    		void setPosition(real x, real y, real z);
    	protected:
    		~Positionable();
    		Position position;
    	};
    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
    class Object : public Positionable, etc...
    	{
    	public:
    		Object();
    		virtual ~Object();
     
    		/// Return a const char*, name of the object type.
    		virtual const char* getName() const = 0;
     
    		/// Search an intersection and eventualy add it to intersect list
    		/// (Objects need a copy of ray in order to change coordinates)
    		virtual void intersec(Ray ray, IntersectionList &it) const = 0;
     
    		/// Compute sphere's normals from an intersection
    		virtual void computeNormals(Intersection &it) const = 0;
    	};
    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
    class Sphere : public Object
    	{
    	public:
    		Sphere(real radius);
    		~Sphere();
     
    		//! Sphere class name
    		static const char* Name;
     
    		virtual const char* getName() const;
     
    		virtual void intersec(Ray ray, IntersectionList &it) const;
    		virtual void computeNormals(Intersection &it) const;
    	private:
    		//! Radius^2
    		real radius;
    		real sq_radius;
    	};
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    class Eye : public Positionable, public Orientable
    	{ //...
    Positionable permet de ne pas écrire dans 4 classe différente comment on modifie une position, etc..
    Maintenant, j'ai pas très envie qu'on manipule des Positionable* car ca na pas de sens de mélanger une lumière, un objet, et la caméra...
    Mes articles Développez | Dernier article : Raytracer en haskell
    Network library : SedNL | Zenol's Blog : http://zenol.fr

    N'oubliez pas de consulter la FAQ et les cours et tutoriels.

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Citation Envoyé par Zenol Voir le message
    Cette dernière phrase est le problème.
    Je ne veut pas que Objet::getPosition soit priver...


    En fait, non... C'est Koala01 qui souhaite à tout prix que mes objets se déplace, sauf qu'ils ne se déplacent pas. (Et ne se déplaceront pas).
    Le code qui manipule un objet, c'est le code de l'utilisateur (Ici je code plus une Lib qu'un programme enfaite.)
    Il est bien question de créer une classe capable de charger une scène depuis un fichier de description/d'écrire une scène dans un fichier, mais c'est une autre histoire dont il ne seras pas question avant un certain temps.
    En fait, j'ai peut être mal exprimé le message que j'essaye de faire passer...

    Ce qui m'embête énormément, c'est la présence de mutateurs, de manière générale, et dans une moindre mesure, la présence d'accesseurs.

    En effet, l'attribut "position" d'un objet ne doit déjà pas forcément etre accessible en lecture, car ton moteur de rendu devrait, en définitive, agir comme un visiteur qui se "contenter" de parcourir les différents objets de ta scene et de leur demander... de s'afficher (au travers d'une methode draw() )

    Mais un mutateur a encore moins à faire dans l'interface, car, l'objet devrait être considéré comme correctement initialisé (comprend: en ce qui concerne la position, qu'il devrait... directement être correctement positionné) et que, si, pour une raison ou une autre, l'attribut d'un objet venait à être modifié "en cours de route" (entre deux rendus), il s'agirait en réalité d'appeler un comportement qui... s'assure de respecter certaines règles et conditions avant de valider le changement.

    Et cette logique est susceptible de s'appliquer à n'importe quel attribut: si modification il y a, elle ne devrait (la plupart du temps) pas être effectuée de manière absolue en précisant un nouvel attribut, mais bien de manière relative (à la "situation propre" de l'objet) et être considérée comme... une transition entre deux états qui seront évalués (au moment du rendu "suivant").

    Fatalement, si modification il y a, il s'agit de considérer le fait qu'un certain intervalle de temps s'écoule entre deux évaluations de l'état, et que cet intervalle mérite, peut être, d'entrer en ligne de compte au moment du calcul de la transition.
    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

  4. #24
    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
    Par défaut
    Citation Envoyé par Zenol Voir le message
    Cette dernière phrase est le problème.
    Je ne veut pas que Objet::getPosition soit priver...
    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
    #include <iostream>
     
    struct base {
        void fonction_1()
        {
            std::cout<<"fonction =1\n";
        }
        void fonction_2()
        {
            std::cout<<"fonction2\n";
        }
    };
     
    struct derivee : private base
    {
        using base::fonction_1;
        using base::fonction_2;
    };
    int main() {
        derivee d;
        d.fonction_1();
        d.fonction_2();
        // base &rb = d;  -> ERREUR
        return 0;
    }

  5. #25
    Membre éclairé
    Avatar de Zenol
    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2004
    Messages
    812
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2004
    Messages : 812
    Par défaut
    Citation Envoyé par koala01 Voir le message
    En fait, j'ai peut être mal exprimé le message que j'essaye de faire passer...

    Ce qui m'embête énormément, c'est la présence de mutateurs, de manière générale, et dans une moindre mesure, la présence d'accesseurs.

    En effet, l'attribut "position" d'un objet ne doit déjà pas forcément etre accessible en lecture, car ton moteur de rendu devrait, en définitive, agir comme un visiteur qui se "contenter" de parcourir les différents objets de ta scene et de leur demander... de s'afficher (au travers d'une methode draw() )

    Mais un mutateur a encore moins à faire dans l'interface, car, l'objet devrait être considéré comme correctement initialisé (comprend: en ce qui concerne la position, qu'il devrait... directement être correctement positionné) et que, si, pour une raison ou une autre, l'attribut d'un objet venait à être modifié "en cours de route" (entre deux rendus), il s'agirait en réalité d'appeler un comportement qui... s'assure de respecter certaines règles et conditions avant de valider le changement.

    Et cette logique est susceptible de s'appliquer à n'importe quel attribut: si modification il y a, elle ne devrait (la plupart du temps) pas être effectuée de manière absolue en précisant un nouvel attribut, mais bien de manière relative (à la "situation propre" de l'objet) et être considérée comme... une transition entre deux états qui seront évalués (au moment du rendu "suivant").

    Fatalement, si modification il y a, il s'agit de considérer le fait qu'un certain intervalle de temps s'écoule entre deux évaluations de l'état, et que cet intervalle mérite, peut être, d'entrer en ligne de compte au moment du calcul de la transition.
    Enfaite, ton draw() est mon intersec() et computeNormal().
    Le moteur n'utilise pas les méthodes setPosition/getPosition. C'est simplement pour que l'utilisateur positionne ses objets dans la scène.
    Et pour ce qui est de considère qu'un objet est complet une fois construit, ce n'est pas "flexible", puisque toute modification du moteur induirais la modification du code d'un utilisateur.

    Et puis, voici un exemple type :
    Une GUI Qt qui utilise le code du moteur pour créer une scène. Rendu avec le moteur en mode "Aucune joli option", et l'application conserve en mémoire la structure de la scène. Il faut bien pouvoir "changer d'avis" sur la position d'un objet, etc.

    il s'agirait en réalité d'appeler un comportement qui... s'assure de respecter certaines règles et conditions avant de valider le changement. -> Qui ne peux être connus que de l'utilisateur, selon ses hypothèses.

    Edit: Enfaite non, tout n'est pas si rose. J'utilise le getter de la couleur dans le moteur de rendu...

    3DArchi> Je m'attendais à ce que tu me dise ca.
    Ce que tu me demande de faire, c'est de faire un using pour toutes les méthodes de base... Et si je rajoute une méthode à base, alors d'aller rajouter ces méthodes dans chacune des classes qui héritent de base...
    Pas très pratique/jolie je trouve...
    Enfaite je pense que l'héritage privé serais raisonnable si la plupart des méthodes était destiné à être utiliser par dérivée (Mais dérivée ne s'en sert pas, seulement des variables membre qui sont ici protected, et de plus doivent le rester)

    HS : A propos de l'article sur les politiques/traits je le garde sous le main, je n'ai pas le souvenir de l'avoir lu mais je le garde sous la main. Pour boost ca fait au moins 1an que je me dis "Un de ces jours, il faudrait que je m'y mette..." mais ca attendras probablement cette été ^^'
    Mes articles Développez | Dernier article : Raytracer en haskell
    Network library : SedNL | Zenol's Blog : http://zenol.fr

    N'oubliez pas de consulter la FAQ et les cours et tutoriels.

  6. #26
    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
    Par défaut
    Citation Envoyé par Zenol Voir le message
    Pas très pratique/jolie je trouve...
    J'ai tendance à être d'accord. Mais, bon, j'ai préféré le présenter...
    Si Object EST-UN Positionnable (LSP, respect du contrat, etc). A la limite, qu'est ce que cela peut te faire qu'un client manipule des Positionable& sans savoir ce qu'ils sont effectivement ?
    En d'autres termes, si l'héritage publique ne pose pas de problème sémantique, fais un héritage publique et ne cherche pas à ce que l'utilisation par la classe de base soit interdit. Mais si la classe dérivée brise la sémantique de la classe de base, alors tu n'as pas le choix : utilise un héritage privé et using pour les méthodes dont le contrat sera respecté.
    Peut être le problème est qu'à la base tu as voulu rajouté une contrainte de trop ?

  7. #27
    Membre éclairé
    Avatar de Zenol
    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2004
    Messages
    812
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2004
    Messages : 812
    Par défaut
    Citation Envoyé par 3DArchi Voir le message
    J'ai tendance à être d'accord. Mais, bon, j'ai préféré le présenter...
    Si Object EST-UN Positionnable (LSP, respect du contrat, etc). A la limite, qu'est ce que cela peut te faire qu'un client manipule des Positionable& sans savoir ce qu'ils sont effectivement ?
    En d'autres termes, si l'héritage publique ne pose pas de problème sémantique, fais un héritage publique et ne cherche pas à ce que l'utilisation par la classe de base soit interdit. Mais si la classe dérivée ne peut être brise la sémantique de la classe de base, alors tu n'as pas le choix : utilise un héritage privé et using pour les méthodes dont le contrat sera respecté.
    Peut être le problème est qu'à la base tu as voulu rajouté une contrainte de trop ?
    Oui tu a certainement raison, ce contrainte est surement de trop.
    Mes articles Développez | Dernier article : Raytracer en haskell
    Network library : SedNL | Zenol's Blog : http://zenol.fr

    N'oubliez pas de consulter la FAQ et les cours et tutoriels.

  8. #28
    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
    Par défaut
    Ceci dit, ce que tu proposais :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    template <class T>
    class Localisable
    {
    // ...
    protected:
      ~Localisable();
    };
    class Object : public Localisable<Object>
    {
    est un hack permettant ce que tu veux. Un Localisable<Object> sera différent d'un Localisable<SpotLight>. Mais j'ai envi de rester sur mon dernier message (qui est un peu la philo du C++) : laisse l'utilisateur se tirer une balle dans le pied avec des Localisable& qui référence des choux et des carottes s'il le souhaite. Toi, tu dois juste garantir que le contrat de Localisable est respecté par les classes qui en dérivent publiquement.

+ Répondre à la discussion
Cette discussion est résolue.
Page 2 sur 2 PremièrePremière 12

Discussions similaires

  1. Réponses: 2
    Dernier message: 09/09/2007, 14h25
  2. Question bateau sur la conversion si possible d'objets
    Par kenny49 dans le forum Langage
    Réponses: 1
    Dernier message: 08/08/2007, 19h20
  3. Réponses: 8
    Dernier message: 04/06/2007, 16h20
  4. Réponses: 24
    Dernier message: 01/06/2007, 09h26
  5. Réponses: 8
    Dernier message: 11/07/2006, 17h27

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