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++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    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 Pas de conversion implicite Objet => Objet& ? | Vtable obligatoire?
    Bonsoir,

    Je me remet doucement au C++ et je me pause quelques petites question.
    Je développe actuellement sou VC++ et j'ai essayer de compiler mon code avec G++(V4.3.2) sous debian.
    J'ai eu quelques surprises (VC++ est bien plus tolérant que g++), dont notamment un refus catégorique du compilateur(G++) de compiler quelque chose comme ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    class C
    {
    public:
    //...
      setPosition(Position &pos);
    };
     
    //...
     
    int main(int argc, char *arv[])
    {
      //...
      aC.setPosition(Position(x, y, z));
      //...
    Le comportement que j'attendrais serais de créer une instance de Position dans la stack, et de passer la référence a la fonction setPosition, avant de détruire l'objet.
    Mais cela ne semble pas du gout de GCC...
    Quand au compilateur de VC++, je ne sais pas non plus si il fait bien cela ou d'autres bidouilles bien louche.

    Du coup, si je veux que la ligne précédente du main compile, je me retrouve a surcharger setPosition pour qu'il prenne un Position par copie.

    ---

    Deuxième petite question, j'ai voulus imposer a ma classe Point3D d'être "Computable", pour ce faire j'ai écris quelque chose dans ce genre :
    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
     
    template <class C, class T>
    class Computable
    {
      //...
      virtual C operator + (const C &c) const = 0;
      virtual C operator * (const T scal) const = 0;
      //...
    };
     
    template <class T>
    class Vector
    {
      virtual ~Vector() = 0;
    };
     
    template <class T>
    inline
    Vector::~Vector()
    {};
     
    //...
    template <class T>
    class Vector3D<T> : public Vector<T>, public Computable< Vector<T>, T>
    {
      //... Implementation des methodes de la forme
     
      //Retourne un nouveau vecteur, C = A + B
      Vector3D<T> operator + (const Vector3D<T> &vec) const;
     
      //Retourne un nouveau vecteur, somme du scalaire sur chacune des coords
      Vector3D<T> operator + (const T scal) const;
     
      //...
    };
    Donc, je me retrouve avec des Vector3D<float> dont je suis assurer de pouvoir les manipuler comme des nombres. (Produit, quotient, différence, somme, comparaison, etc...)

    Je ne sais pas si c'est très propre, j'y suis aller a l'instinct, mais d'après le debugger de VC++, Vect3D contient deux pointeurs vers une vtable, un pour chacun de ses parents.
    J'ai zapper quelque chose qui implique que Vector3D doit nécessairement avoir un pointeur sur la Vtable de Computable? (Parce qu'en fin de compte, il n'y a aucune méthode implémenté dans Computable, c'est un peu comme une "interface"...)

    Voila, ce sont mes questions existentiel de la journée.
    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.

  2. #2
    Membre chevronné Avatar de Lavock
    Profil pro
    Inscrit en
    Octobre 2009
    Messages
    560
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2009
    Messages : 560
    Par défaut
    1 - Je suis plutôt scandalisé que vc l'accepte >< !!!

    La norme dit qu'une reference (appelé maintenant lvalue reference) peut référencer... une lvalue.
    Une référence constante peut, elle référencé n'importe quoi.

    Déjà, il est sensé être plus rentable de prendre une copie. Dans se cas là, je crois que les compilateurs sont obligé par la norme de ne faire qu'une construction, et non une copie plus une construction.

    Ensuite, si tu veux garder des références, je te conseille de regarder du côté de C++0x et des rvalue reference.

    2 - Je ne connais pas VC, mais dans les ressource de 3DArchi tu vas trouver un gros article sur le mot clef "virtual" et tutti quanti. Regarde si ton bonheur ne s'y trouve pas !

  3. #3
    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
    Salut,

    En fait, une toute petite modification de ton code suffirait pour que tout rentre dans l'ordre (bon, il faut la répercuter à deux endroits ):

    "simplement" ajouter le mot clé const soit avant le terme Position, soit (de préférence) entre le terme position et le caractère "&".

    Si je dis qu'il faut le faire deux fois, c'est parce qu'il faut le faire... pour la déclaration de la fonction, et pour... son implémentation.

    En effet, le code
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    aC.setPosition(Position(x, y, z));
    va créer ce que l'on appelle une variable temporaire anonyme:

    Temporaire parce que... elle n'existe que pour la durée de l'exécution de... setPosition
    Anonyme parce que... on ne dispose d'aucun identifiant nous permettant... d'y accéder en dehors de l'appel de la fonction (comme, en plus, elle n'existe pas en dehors de l'appel de la fonction, c'est à peu près normal )

    Or, les auteurs de la norme ont estimé que, comme il n'y a aucun moyen de récupérer, dans la fonction appelante (main, selon ton exemple), les modifications qui pourraient être apportées durant la fonction appelée (setPosition, en l'occurrence), il n'y a... aucun avantage à... permettre à la fonction appelée (je parle toujours de setPosition) de modifier une telle variable temporaire anonyme.

    Du coup, ils ont décidé que l'on pourrait provoquer la création d'une variable temporaire anonyme en passant une référence sur un objet (il faut, ici, se rappeler qu'une référence est un alias d'un objet, et que, par conséquent, l'objet référencé doit... exister...) uniquement si... la référence en question est constante.

    Ainsi donc, en modifiant ta classe en
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    class C
    {
    public:
    //...
      void setPosition(Position const & pos);
    };
    et, fatalement, en modifiant, en modifiant l'implémentation de la fonction en
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    void C::setPosition(Position const & pos)
    {
        /*... ce qui doit être fait */
    }
    tu respectera la norme, et tu n'aura plus de problème à la compilation

    Ceci étant dit, j'ai personnellement horreur des mutateurs, surtout s'il s'exposent trop ostensiblement à coup de setMachinChose, et que je suis très attentif à la sémantique des différents identifiants utilisés.

    Au départ du code que tu nous montre, on peut, effectivement, estimer que:
    • la classe C devrait avoir une position de départ... Il serait pas mal d'envisager de mettre RAII en oeuvre
    • Une instance de la classe C est, visiblement, susceptible de se déplacer... Peut être faudrait-il se poser la question de la manière dont elle le fait. Est-ce:
      • vers des positions "relatives" (à la position actuelle)
      • vers des position "absolues"
    Selon la réponse que tu donnera à cette deuxième question, peut être serait il intéressant d'envisager l'utilisation d'une fonction move() (même si on ne fait que renommer setPositon), parce qu'elle est plus expressive de ce qui se fait
    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. #4
    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 Lavock
    1 - Je suis plutôt scandalisé que vc l'accepte >< !!!

    La norme dit qu'une reference (appelé maintenant lvalue reference) peut référencer... une lvalue.
    Une référence constante peut, elle référencé n'importe quoi.

    Déjà, il est sensé être plus rentable de prendre une copie. Dans se cas là, je crois que les compilateurs sont obligé par la norme de ne faire qu'une construction, et non une copie plus une construction.

    Ensuite, si tu veux garder des références, je te conseille de regarder du côté de C++0x et des rvalue reference.

    2 - Je ne connais pas VC, mais dans les ressource de 3DArchi tu vas trouver un gros article sur le mot clef "virtual" et tutti quanti. Regarde si ton bonheur ne s'y trouve pas !
    1 - Ah bah, je ne savais pas! Si la norme le dis, la norme est renne, j'obtempère sur le champ.
    2 - Ok je vais aller voire ca.

    Citation Envoyé par koala01 Voir le message
    Salut,

    En fait, une toute petite modification de ton code suffirait pour que tout rentre dans l'ordre (bon, il faut la répercuter à deux endroits ):

    "simplement" ajouter le mot clé const soit avant le terme Position, soit (de préférence) entre le terme position et le caractère "&".

    Si je dis qu'il faut le faire deux fois, c'est parce qu'il faut le faire... pour la déclaration de la fonction, et pour... son implémentation.

    En effet, le code ... va créer ce que l'on appelle une variable temporaire anonyme:

    Temporaire parce que... elle n'existe que pour la durée de l'exécution de... setPosition
    Anonyme parce que... on ne dispose d'aucun identifiant nous permettant... d'y accéder en dehors de l'appel de la fonction (comme, en plus, elle n'existe pas en dehors de l'appel de la fonction, c'est à peu près normal )

    Or, les auteurs de la norme ont estimé que, aucun moyen de récupérer, dans la fonction appelante (main, selon ton exemple), les modifications qui pourraient être apportée durant la fonction appelée (setPosition, en l'occurence), il n'y a... aucun avantage à... permettre à la fonction appelée (je parle toujours de setPosition) de modifier une telle variable temporaire anonyme.

    Du coup, ils ont décidé que l'on pourrait provoquer la création d'une variable temporaire anonyme en passant une référence sur un objet (il faut, ici, se rappeler qu'une référence est un alias d'un objet, et que, par conséquent, l'objet référencé doit... exister...) uniquement si... la référnce en question est constante.

    Ceci étant dit, j'ai personnellement horreur des mutateurs, surtout s'il s'exposent trop ostensiblement à coup de setMachinChose, et que je suis très attentif à la sémantique des différents identifiants utilisés.

    Au départ du code que tu nous montre, on peut, effectivement, estimer que:
    • la classe C devrait avoir une position de départ... Il serait pas mal d'envisager de mettre RAII en oeuvre
    • Une instance de la classe C est, visiblement, susceptible de se déplacer... Peut être faudrait-il se poser la question de la manière dont elle le fait. Est-ce:
      • vers des positions "relatives" (à la position actuelle)
      • vers des position "absolues"
    Selon la réponse que tu donnera à cette deuxième question, peut être serait il intéressant d'envisager l'utilisation d'une fonction move() (même si on ne fait que renommer setPositon), parce qu'elle est plus expressive de ce qui se fait
    Merci pour ces précision sur les variables anonyme. C'est effectivement ce comportement que je recherchais, pour pouvoir au choix utiliser un objet existant ou bien un objet qui ne serait crée que le temps de l'appelle, et donc être assuré de l'absence de copie superflue.

    Sinon, pour répondre a tes questions :
    • la classe C devrait avoir une position de départ... Il serait pas mal d'envisager de mettre RAII en oeuvre

      => Enfaite, le constructeur est déjà un peux prit par d'autres choses pour les classes filles, et si je ne veux pas me retrouver avec deux lignes de paramètre a la construction, je vais me contenter de dire que tout C est positionné à l'origine. (Si j'ai bien comprit ce que tu voulais dire par RAII ^^')
    • Une instance de la classe C est, visiblement, susceptible de se déplacer...

      => Hum, pas vraiment enfaite. Elle a une place définie, mais on peut décider que finalement ca ne nous plait pas et donc d'en définir une autre.
      Bien sur, dans un second temps on peut envisager qu'effectivement l'objet se déplace. Mais dans ce contexte précis (Qui vraisemblablement finiras par arriver... du moins j'aimerais bien ^^) on considèreras qu'un intervalle de temps est composé de point discret et en chacun de ces point, tout les C on des positions précise fixé. (Et de plus une orientations, et des caractéristiques, propres à tout C et objet héritant de C)
    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.

  5. #5
    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
    • la classe C devrait avoir une position de départ... Il serait pas mal d'envisager de mettre RAII en oeuvre

      => Enfaite, le constructeur est déjà un peux prit par d'autres choses pour les classes filles, et si je ne veux pas me retrouver avec deux lignes de paramètre a la construction, je vais me contenter de dire que tout C est positionné à l'origine. (Si j'ai bien comprit ce que tu voulais dire par RAII ^^')
    Le constructeur de la classe mère est pris par... des arguments nécessaires aux classe fille

    Tu n'a pas un peu l'impression que ce devrait etre le contraire

    De même, tu n'as pas un peut l'impression que tu en demande... peut être un peu trop à ta classe mère
    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

  6. #6
    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
    Au fait, cette entrée de la FAQ explique ce que l'on entend par RAII.

    Ce concept tend à veiller à ce que, quel que soit l'objet créé, il le soit de manière à être directement utilisable et qu'il présente, autant que faire se peut, des attributs correspondant à un "état primitif" intéressant dans le contexte dans lequel l'objet est créé.

    Le principe est à mettre en parallèle avec son homologue concernant la destruction que nous pourrions nommer (s'il était officiellement reconnu) DIRR (Destruction Is Ressource Release) et qui a pour but de veiller, lors de la destruction d'un objets, à ce que toutes les ressources "accaparées" par l'objet soient... correctement libérées.
    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

  7. #7
    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
    Ah oui, j'avais zapper le warning. (Je préfère quand le compilateur me gueule l'erreur plutôt que lorsqu'il me la murmure. (Je peut pas non plus lui dire de s'arrêter au moindre warning, car pour faire du debug j'ai tendance a abuser de ces derniers ^^')

    Citation Envoyé par koala01 Voir le message
    Le constructeur de la classe mère est pris par... des arguments nécessaires aux classe fille
    Non, mais elle est abstraite. Je ne vois pas en quoi pouvoir affecter une position a la classe mère via son constructeur peut être utile, puisque ce constructeur si il existe ne seras appeler que par le constructeur de la classe fille.
    Citation Envoyé par koala01 Voir le message
    Tu n'a pas un peu l'impression que ce devrait être le contraire

    De même, tu n'as pas un peut l'impression que tu en demande... peut être un peu trop à ta classe mère
    Ma classe mère définie ce qu'est et ce que doit avoir toute classe fille, qui implémente ses méthodes.

    (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.)

    Donc non je n'ai pas l'impression qu'elle fasse trop de chose. Enfaite, elle ne fait pas grand chose a part lister des méthodes virtuels pure, contenir des variables protected et définir les accesseur/mutateurs de ces variables. (Enfaite pour rendre le tout plus lisible elle hérite de deux classes, "Positionable" et "Orientable" qui elles ont leur destructeur non virtuel protégé.)

    Sinon, pour 2), j'ai lut le document en question (très intéressent au passage, si bien que je me retrouve avec une question supplémentaire ^^') mais je n'ai rien trouver qui puisse résoudre mon problème.
    Au pire je peux me décide a passer le destructeur private pour éviter que l'on tente de détruire des objets Computable&|*, mais je ne vois pas trop comment dire au compilo que ca ne sert a rien de faire un pointeur de vtable pour les classes qui hérite. Je me demande si il n'y aurais pas moyen de faire exactement la même chose sans virtual avec uniquement des template...

    Enfin, une petite question sur les vtable et les pointeurs.
    Si j'ai
    class A
    class B
    class C : public A, public B
    Out toute ces classe contienne des méthodes virtuel.
    Supposon que les pointeurs sur vtable se situent au debut des objets.
    Soit this, une instance de C, on a alors :
    (void*)(this) un pointeur sur vtable de B
    (void*)((long int*)this + 4) un pointeur sur vtable de A.

    La question que je me pose est : comment le compilo gère un de type A* sur un membre de C et un pointeur de type B* sur un membre de C?
    Si pour A* la réponse est simple (Il suffit de considérer (int*)this+4 et lors d'un downcasting on calcule this-4) la réponse n'est pas si évidente pour B...
    La solution qui me viens a l'esprit c'est "on swap *(int*)(this) et *((int*)this + 4) puis on calcule this+4" et l'opération réciproque pour du downcasting.
    Qu'en est-il de la réalité? (Avec GCC par exemple)

    Edit : J'ai déjà lut la FAQ sur RAII, mais justement je vois pas vraiment ce que ca viens faire dans mon cas. Ici la ressource est une Position, qui possède son constructeur, qui s'initialise toute seule avec les bonnes valeurs, et qui se détruit toute seul. Je pourrais ajouter les paramètre pour l'initialiser dans le constructeur de Object, mais c'est inutile car on ne peut pas créer un ClasseMere, mais seulement des ClasseFille. Si je voulais donc faire remonter l'info jusqu'au constructeur de Position, il me faudrait traverser toute une hiérarchie de constructeur et bien sur ajouter ces paramètres au constructeur de chacune de mes classes filles (Et il vas y en avoir beaucoup des classes filles!)
    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. #8
    Membre Expert

    Inscrit en
    Mai 2008
    Messages
    1 014
    Détails du profil
    Informations forums :
    Inscription : Mai 2008
    Messages : 1 014
    Par défaut
    Citation Envoyé par Zenol Voir le message
    J'ai eu quelques surprises (VC++ est bien plus tolérant que g++)
    C'est un peu exagéré. Sur un tel code, VC++ avertit par un warning très explicite qu'il est en train d'utiliser une extension non standard "warning C4239: nonstandard extension used : 'argument' : conversion from 'Position' to 'Position &'"

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

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