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 :

Heritage en chaine


Sujet :

Langage C++

  1. #1
    Membre régulier
    Homme Profil pro
    Second de cuisine
    Inscrit en
    Avril 2005
    Messages
    193
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Second de cuisine
    Secteur : Alimentation

    Informations forums :
    Inscription : Avril 2005
    Messages : 193
    Points : 99
    Points
    99
    Par défaut Heritage en chaine
    Bonjour,

    Voici les classes héritées:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    template<typename Cast, typename IdType>
    struct shared_pointer
    {
    	typedef std::shared_ptr<Cast> ptr;
    	typedef IdType id_t;
    };
    Puis,
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    class sprite: public shared_pointer<sprite, long_t>
    Et enfin
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    class complete_sprite: sprite
    Et maintenant, quand je tente de creer un objet de type complete_sprite:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    complete_sprite::ptr complete_sprite::create(
            const sf::Texture& texture,
            const std::vector<std::string>& groups,
            const std::string& first_group,
            short_t frames,
            functor left_click,
            functor right_click,
            functor double_lclick,
            functor double_rclick
        )
    {
        return std::make_shared<complete_sprite>(texture, groups, first_group, frames, left_click, right_click, double_lclick, double_rclick);
    }
    Le compilateur me sors:
    /media/data/dev/projects/Tools/game/sprites/complete.cpp|37|error: could not convert ‘std::make_shared(_Args&& ...) [with _Tp = game::sprites::complete_sprite; _Args = {const sf::Texture&, const std::vector<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >&, const std::basic_string<char, std::char_traits<char>, std::allocator<char> >&, unsigned char&, std::function<void(game::sprites::sprite&)>&, std::function<void(game::sprites::sprite&)>&, std::function<void(game::sprites::sprite&)>&, std::function<void(game::sprites::sprite&)>&}]((* & groups), (* & first_group), (* & frames), (* & left_click), (* & right_click), (* & double_lclick), (* & double_rclick))’ from ‘std::shared_ptr<game::sprites::complete_sprite>’ to ‘shared_pointer<game::sprites::sprite, long unsigned int>::ptr {aka std::shared_ptr<game::sprites::sprite>}’|
    Ou pour faire plus court...
    error: could not convert

    ‘std::make_shared(_Args&& ...)((* & groups), (* & first_group), (* & frames), (* & left_click), (* & right_click), (* & double_lclick), (* & double_rclick))’

    from

    ‘std::shared_ptr<game::sprites::complete_sprite>’

    to

    ‘shared_pointer<game::sprites::sprite, long unsigned int>::ptr {aka std::shared_ptr<game::sprites::sprite>}’|
    Qu'est-ce qui cloche ?

    Merci, nico

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

    Informations professionnelles :
    Activité : aucun

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

    Tu n'as pas spécifié la visibilité de l'héritage

    Comme complete_sprite est une classe, c'est l'héritage par défaut qui est utilisé, et c'est donc un héritage privé.

    La sémantique d'un tel héritage n'a plus rien à voir avec une hiérarchie de classes (des relations EST-UN), mais est plus proche d'une sémantique de "est implémenté en terme de".

    Cela revient strictement au même que si tu avais
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    class A: public shared_pointer<sprite, long_t>{
        /* ... */
    };
    class B{ //pas d'héritage du tout !!!
    public:
        A::ptr create(){
            return make_shared<B>(/* ... */);
        }
    };
    A partir de là, complete_sprite est un type totalement différent de sprite, et il est donc tout à fait normal que ton compilateur fasse sa mauvaise tête .

    Mais peut etre n'est-ce juste qu'un copier coller foireux

    Ceci dit, j'ai toujours été relativement opposé à une éventuelle fonction create dont le but serait de renvoyer un pointeur sur un nouvel objet, surtout lorsqu'il y a tant de paramètres à donner.

    Autant je comprend la présence d'une fonction clone dont le but est de créer un "clone parfait" de l'objet existant afin de lui permettre sa propre vie, autant j'estime qu'il ne devrait jamais être de la responsabilité d'une classe de créer une nouvelle instance d'elle-même (en dehors du phénomène de clonage, bien sur).

    C'est d'autant plus vrai ici que ton code l'indique bien: tu veux travailler avec des pointeurs intelligents sur... sprite.

    Or, si tu as créé une classe complete_sprite, il n'y a rien qui nous interdit de penser qu'il y aura, un jour peut etre, une autre classe qui dérivera de sprite et dont la fonction create pourrait nécessiter des paramètres différents en types et/ou en nombre.

    Tu te trouveras donc, tot ou tard (si ce n'est pas déjà fait) face à la nécessité absolue de connaitre complete_sprite (ou tout autre type dérivée de sprite) pour pouvoir en créer une nouvelle instance, ce qui implique une dépendance regrettable envers ces classes étant donné que tu espères pouvoir te contenter de manipuler les objets en ne les connaissant que comme étant du type parent.

    Peut etre devrais tu envisager le patron de conception fabrique pour éviter ce genre de dépendances malheureuses
    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

  3. #3
    Membre régulier
    Homme Profil pro
    Second de cuisine
    Inscrit en
    Avril 2005
    Messages
    193
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Second de cuisine
    Secteur : Alimentation

    Informations forums :
    Inscription : Avril 2005
    Messages : 193
    Points : 99
    Points
    99
    Par défaut
    En fait, c'est GCC4.7.3 qui fait des siennes.
    La solution est:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    return sprite::ptr(new sprite(texture, groups, first_group, frames, left_click, right_click, double_lclick, double_rclick));
    Mais l'explication .. aucune idée :s

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Non, en fait, c'est tout à fait normal (je considère donc que complete_sprite hérite bel et bien publiquement de sprite et que ce n'était qu'une erreur de copie dans ton intervention précédente )

    make_shared, tel que tu l'utilises, va essayer de créer un std::shared_ptr<complete_sprite> mais ton typedef "sprite::ptr" correspond à un std::shared_ptr<sprite>.

    Or, même s'il y a une relation d'héritage entre les classe A et B, une classe template C fournira deux types qui n'ont rien à voir l'un avec l'autre si elle est spécialisée avec un A (C<A>) ou avec un B (C<B>).

    La raison est toute simple: Tu peux parfaitement utiliser un objet du type template par valeur dans la fonction ou dans la structure template que tu crées:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    template <typename T>
    struct S{
        T t;
        void operator()(){
            t.doSomenthing();
        }
    };
    template <typename T>
    void foo(T t){
    /* n'importe quelle manipulation de t */
    }
    Dans un tel contexte,
    1. tu dis adieu au polymorphisme (parce que ce n'est ni un pointeur ni une référence), mais surtout
    2. tu cours le risque de voir apparaitre un phénomène de slicing: l'objet de type dérivé serait vu et considéré comme étant un objet du type de base.
    3. L'espace mémoire utilisé par un objet du type de base a de très grandes chances d'être différent de l'espace mémoire utilisé par un objet du type dérivé
    Ce qu'il faut bien comprendre, c'est que cette règle de base tout à fait logique a été édictée bien avant que C++ ne propose la moindre notion de pointeurs intelligents de manière standard.

    S'il avait fallu amender cette règle avec une exception qui prévoie le cas explicite où l'on a la certitude de travailler sur des pointeurs (comme c'est le cas pour les shared_ptr), cela aurait foutu un sérieux bordel en terme d'implémentation

    Toujours est il que, même si les pointeurs ont une taille clairement définie, les classes de pointeurs intelligents (et les éventuelles fonctions libres qui les manipulent) restent malgré tout soumises à cette contrainte particulière.

    Tu ne peux donc pas utiliser le std::shared_ptr<complete_sprite> renvoyé par std::make_shared là où un std::shared_ptr<sprite> (le typedef sprite::ptr) est attendu

    Par contre, si tu utilises le constructeur de shared_ptr qui attend un pointeur du type indiqué comme paramètre (comme ce que tu fais dans ta réponse), à ce moment là, tu profites effectivement de la possibilité de faire passer ton pointeur sur un objet de type complete_sprite pour un pointeur sur un objet de type sprite grâce à la substituabilité des pointeurs et des références vers les types dérivés
    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

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

Discussions similaires

  1. probleme d'heritage sur des chaines de caracteres
    Par pikiwiki dans le forum C++
    Réponses: 3
    Dernier message: 24/05/2006, 21h01
  2. tri de liste chainée
    Par RezzA dans le forum C
    Réponses: 7
    Dernier message: 26/01/2003, 20h25
  3. [TP]lire une ligne de l'ecran et la stocker dans une chaine
    Par Bleuarff dans le forum Turbo Pascal
    Réponses: 26
    Dernier message: 02/07/2002, 10h08
  4. Réponses: 3
    Dernier message: 12/06/2002, 21h15
  5. Probleme sur les chaines de caractere
    Par scorpiwolf dans le forum C
    Réponses: 8
    Dernier message: 06/05/2002, 19h01

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