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 :

membre constexpr et héritage


Sujet :

C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éclairé Avatar de BioKore
    Homme Profil pro
    Dresseur d'Alpaga
    Inscrit en
    Septembre 2016
    Messages
    300
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Canada

    Informations professionnelles :
    Activité : Dresseur d'Alpaga

    Informations forums :
    Inscription : Septembre 2016
    Messages : 300
    Par défaut membre constexpr et héritage
    Bonjour à tous,

    Dans le cadre de mon projet, je souhaite pouvoir identifier certaines classes avec des ID uniques déterminés à la compilation, statiques à classe considérée et surtout non modifiables.

    Jusque là, je m'en sort bien. J'ai une fonction de hachage qui me permet, via une macro, de réaliser ce que je souhaite :
    #define SIGNATURE_TAG(val) static constexpr std::size_t signature = strhash(#val)Par contre, là où ça se corse, c'est que ces différentes classes doivent hériter d'un parent permettant d'accéder à ces valeurs. Si je reprends la macro ci-dessus, j'ai :

    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
    #define SIGNATURE_TAG(val) static constexpr std::size_t signature = strhash(#val)
     
    struct A
    {
    	/* que faire ici pour pouvoir accéder à "signature" */
    	//[...]
    };
     
    struct B: A
    {
    	SIGNATURE_TAG("premier hash");
    };
     
    struct C: A
    {
    	SIGNATURE_TAG("second hash");
    };
     
     
    int main()
    {
    	std::vector<A> vals;
    	vals.push_back(B);
    	vals.push_back(B);
    	vals.push_back(C);
     
    	for(auto a:vals_)
    	{
    		std::cout << a::signature << std::endl;
    	}
     
    	return 0;
    }
    si je renseigne une variable "signature" dans A, alors j'ai un conflit, mais si je ne le renseigne pas, je ne peux donc pas accéder aux valeurs nécessaires pour le bon déroulement de mon programme...

    Autre bug que je retrouve, en parallèle, c'est lors du passage d'une des structures (B, ou C) via référence ou pointeurs à une fonction, je ne récupère pas les mêmes valeurs. Ceci me surprends beaucoup, aussi je pense que cette dernière problématique est en partie liée à la première.


    Une idée ?

    Merci d'avance.

  2. #2
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 149
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 149
    Billets dans le blog
    4
    Par défaut
    Salut,

    en gros tu veux réimplémenter du RTTI ?
    Ce que je fais dans ces cas c'est une macro DECLARE comme tu l'as, mais il faut aussi une fonction virtuelle qui retourne ceci.
    Grosso merdo rapidement non testé du genre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    #define DECLARE_RTTI(classname, parent) \
    static constexpr size_t ClassId = hash(#classname ## #parent); \
    size_t GetClassId() const override { return ClassId; }
     
    #define DECLARE_RTTI_ROOT(classname) \
    static constexpr size_t ClassId = hash(#classname ## #parent); \
    virtual size_t GetClassId() const { return ClassId; }
    Ensuite tu as généralement les fonction IsA, Cast, etc qui s'ajoutent.

    Sinon ce pourrait aussi être le moment d'utiliser du CRTP.

    Mais on n'a pas assez d'infos pour choisir à ta place..
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  3. #3
    Membre Expert
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2011
    Messages
    760
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

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

    Informations forums :
    Inscription : Juin 2011
    Messages : 760
    Par défaut
    vals ne contient pas des B ou C, mais des A. L'héritage devrait se faire sous 2 conditions:
    - une base qui possède des fonctions membres virtuelles et par conséquent pas d'opérateur et constructeur de copie, mais un destructeur virtuel. Sans ces interdits, il y aura slicing (perte d'info par changement de type via copie).
    - un héritage privé dans le cas contraire

    Seul le point 1 permet de garder des informations et comportement à travers une classe de base. Par conséquent, vals ne peut pas être un std::vector de A, mais de référence sur A (std::reference_wrapper, unique_ptr, raw pointer, etc)..

    Ensuite a dans la boucle est de type A et signature un membre statique. Par conséquent, le compilateur va chercher le membre dans A. Si a était une référence qui pointe sur un type B, le compilateur irait quand même chercher signature dans A, car a serait une référence de type A& et donc de type A: les membres statiques ne sont pas associés à une instance mais au type utilisé.

    Comme on ne sait absolument pas le besoin, je balance juste en vrac quelques méthodes utilisées:
    - std::variant
    - une espèce de std::any
    - du polymorphisme sur une fonction signature
    - du polymorphisme et un passage du hash en paramètre au constructeur de A.

  4. #4
    Membre éclairé Avatar de BioKore
    Homme Profil pro
    Dresseur d'Alpaga
    Inscrit en
    Septembre 2016
    Messages
    300
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Canada

    Informations professionnelles :
    Activité : Dresseur d'Alpaga

    Informations forums :
    Inscription : Septembre 2016
    Messages : 300
    Par défaut
    Ok, merci pour tous ces retours. A la base, tenant tout particulièrement à conserver ces structures extrêmement triviales, je souhaite pouvoir avoir un accès direct aux membres, sans passer par des fonctions. Ce que je cherche à faire avec ça est un ECS (restant simpliste mais fonctionnel, sans prétention).

    Le but final de tout ça, c'est de pouvoir créer des composants simples, avec un type commun permettant de les stocker dans un unique vecteur (c'est plus pratique quand on commence à avoir pas mal de composants...), mais conservant une information unique permettant d'identifier chaque type de composant (plus loin dans le code, ces derniers seront finalement classés par type, ou plus exactement, des pointeurs ou des références vers les composants seront classés par types).

    Tel que je m'imagine la chose, lors du traitement, je pensais faire une fonction de ce type :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    template<typename CTYPE, typename ...REST>
    bool processNewComponent(Component & cmp)
    {
    	if(CTYPE::signature == cmp.signature)
    	{
    		return true;
    	}
    	else
    	{
    		return processNewComponent<REST...>(cmp);
    	}
    }

    de cette manière on sait si le composant traité fait parti ou non du vecteur de recherche.

    Étant encore en train de travailler sur ce code, je n'ai pas vraiment de version complète ou finale à fournir. Pour le moment, je cherche à définir une première orientation et valider (ou non) une idée.


    Au passage, effectivement, je me rends compte que, dans un vecteur de A (pour reprendre le premier exemple), la valeur retournée est bien celle de A::signature... J'obtiens donc bien effectivement, soit A::signature, soit un joli message de mon éditeur de lien qui me dit "undefined reference to B::signature"...

  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
    Salut,

    J'ai une question idiote : pourquoi voudrais tu faire quelque chose dans le genre

    Car, a priori, tu n'en as absolument pas besoin! Je m'explique:

    Chaque objet connaît obligatoirement le type réel dont il est issu, et donc, les fonctions polymorphes -- les fonctions virtuelles déclarées dans la classe de base, dont le comportement est redéfini au niveau de la classe dérivée -- suffisent amplement dans la plupart des cas.

    Au pire, tu te retrouves dans une situation dans laquelle tu as "été assez bête" que pour perdre l'information directe concernant le type réel de l'objet. Par exemple, parce que tu as décidé de placer tous les objets créés dans une collection de "pointeurs vers le type de base". Et, dans ce cas, la seule solution raisonnable de travailler (qui respecte l'OCP) sera de profiter du fait que chaque objet connaît son type réel pour passer par le double dispatch.

    Toute tentative de sélection d'un comportement particulier sur base d'une information de type est -- par nature -- vouée à termes à la catastrophe. Pourquoi, me demanderas tu sans doute?

    Hé bien, tout simplement parce que tu vas sans doute commencer par deux (trois, quatre, cinq) classes qui renverront les identifiants [c]class1[c], [c]class2[c]... [c]class5[c], et par un comportement qui ressemblerait à un test à choix multiple (ou une série de if ..; else) proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    switch(obj->id()){
        case class1:
            static_cast<Class1 *>(obj)->truc();
            break;
        case class2:
            static_cast<Class2 *>(obj)->machin();
            break;
           /* ... */
        case class5:
            static_cast<Class5 *>(obj)->bidule();
            break;
    }
    Jusque là, tu n'aurais sans doute pas trop de problème. Sauf que ce genre de code va se retrouver, au fil du temps, à cinq, dix, trente endroits différents dans ton code.

    Puis, un jour, tu vas te rendre compte que tu as besoin d'une nouvelle classe (dont l'identifiant est class6) qui exposent ses propres comportements tout à fait spécifiques.

    Avec "un peu de chance", tu te souviendra du dernier endroit où tu as mis ce genre de logique en place. Et tu iras donc directement à cet endroit du code pour rajouter le
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    case class6:
        static_cast<Class6 *>(obj)->brol()
        break;
    correspondant.

    C'est cool, non Mais, tu ne pensera absolument pas aux ... (vingt-)neuf autres endroits du code qui nécessitent une adaptation similaire. Et il n'y aura absolument rien qui te permette de te rendre compte de ton oubli.

    La seule chose, c'est que, à un moment de l'exécution, tu pourras éventuellement te rendre compte que ton objet de type Classe6 aurait du subir une modification quelconque, aurait du faire partie d'une action quelconque, et que ce n'est pas le cas. Et le pire de l'histoire, c'est que, avant que tu ne t'en rende compte, il pourrait très bien s'être déjà écoulé plusieurs mois!

    Tu vas donc perdre deux bonnes heures dans une folle séance de débug (qui te fera sans doute attraper un ou deux cheveux gris par la même occasion) avant de trouver l'endroit du code où tu dois ajouter le choix class6. Et, après, tu sera content et fer de toi, car, selon toute évidence, ton programme devrait fonctionner correctement! Mais non! Parce qu'il y a toujours ... (vingt-)sept autres endroits dans le code dans lesquels ce choix n'apparaît pas. Et il te faudra sans doute encore plusieurs mois avant de te rendre compte que ce choix manque "quelque part".

    Au final, une décision prise aujourd'hui, qui peut sembler parfaitement cohérente, va revenir te hanter et te pourrir la vie pendant des années (en fait, aussi longtemps que l'application sera utilisée), en (re)venant te péter à la figure de manière très régulière. Ce n'est pas le genre de chose que l'on souhaite. Et c'est d'autant plus idiot qu'il existe suffisamment de moyens d'éviter le problème.

    Maintenant, tu as peut-être d'excellentes raisons pour vouloir identifier spécifiquement les différentes classes. Par exemple, pour mettre en place une sorte de factory, mais à la condition expresse que cette identifiant ne serve qu'à cela! Et c'est la raison pour laquelle je te pose la question de savoir pourquoi tu voudrais faire une chose pareille. Qui sait, avec un peu de chance, nous pourrons t'indiquer le moyen de t'en passer une fois que nous aurons compris le besoin que tu cherches à remplir au travers de cette solution
    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
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2009
    Messages
    4 493
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Loire Atlantique (Pays de la Loire)

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

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 493
    Billets dans le blog
    1
    Par défaut
    Je rejoins Koala : pourquoi veux-tu faire ça ?

    Identifier une classe, ça peut se faire facilement avec https://en.cppreference.com/w/cpp/language/typeid

    Vouloir dans des classes dérivées connaitre les identifiants des classes mères, ça ressemble à une mauvaise solution à un mauvais problème. Avant de te lancer dans un truc compliqué, reviens à la base pour voir si tu as vraiment besoin de faire ça. Dis-nous en plus, qu'on puisse te donner un avis plus global

  7. #7
    Membre éclairé Avatar de BioKore
    Homme Profil pro
    Dresseur d'Alpaga
    Inscrit en
    Septembre 2016
    Messages
    300
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Canada

    Informations professionnelles :
    Activité : Dresseur d'Alpaga

    Informations forums :
    Inscription : Septembre 2016
    Messages : 300
    Par défaut
    Bonjour à tous, et merci pour ces échanges.

    En fait, je réuni ici plusieurs objectifs, et, ci-dessous, je vous présenterais en fin la finalité (le code) de ce que je souhaite concrètement mettre en place (une fois que j'aurais répondu à la problématique posée dans ce fil).

    • Les composants, de type différents et substituables à un "composant originel" doivent pouvoir être stockés sous un seul et même container
    • Les systèmes peuvent être créés de manière simple, à volonté, sans avoir à se soucier de la manière dont ils vont chercher les composants nécessaires à leur fonctionnement
    • Les entités sont, pour moi, une classe qui contiens à minima un index d'entité + une liste de pointeurs vers les composants qui "structurent" la-dite entité.


    pour mettre tout ça en place, je présenterais donc, un "Manager", qui n'est finalement rien d'autre qu'une interface au sens propre (ou figuré ???) du terme, qui servira de point d'entré unique ou presque à l'utilisateur. Cette classe ne me semble, à priori, triviale pour le moment ; j'en présenterais tout de même le code actuel, permettant de voir comment sont stockés les différents éléments.

    Classe Manager :
    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
    class Manager
    {
    private:
     
     
    	std::vector<std::vector<BaseComponent> > m_component;
    	std::vector<ISystem> m_system;
     
    public:
     
    	// no parameters for CTors / DTors ?
    	Manager() = default;
    	~Manager() = default;
     
     
    	Entity & createEntity();
     
    	bool addNewComponent(BaseComponent & newComponent);
     
    	//NEXT : finish implementation... 
     
    };
    Bien entendu, pour tout ça nous devons présenter aussi les composants, tels que je les ait déjà présentés plus haut :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    class BaseComponent
    {
    	// ?????
    };
     
    class myNewComponent: BaseComponent
    {
    	static constexpr std::size_t signature = hash(myNewComponent);
    	// or
    	// signature = get_typed_id<myNewComponent>();
    };

    Rien de bien nouveau ici. Cependant, voici la classe BaseSystem ci-dessous :


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    template<typename ...SYSTEM_CTYPES>
    class BaseSystem: public ISystem
    {
    protected:
     
    	using componentTuple_t = std::tuple<SYSTEM_CTYPES&...>;
    	std::vector<componentTuple_t> m_componentTuples;
     
     
    public:
    	explicit BaseSystem() {}
    	virtual ~BaseSystem() {}
     
    	virtual bool addNewComponent(componentTag_t const & tag, BaseComponent* newComponent/*, Other thing ?*/) override final;
     
    	template<std::size_t PROCESS_ID, typename CTYPE, typename ...OTHER_CTYPES>
    	bool processNewComponent(componentTag_t const & tag, BaseComponent* newComponent/*, Other thing ?*/) ;
     
    	template<std::size_t PROCESS_ID>
    	bool processNewComponent(componentTag_t const & tag, BaseComponent* newComponent/*, Other thing ?*/);
     
    	// virtual void update() = 0; // implement it in the final system only
     
     
    };
     
     
     
    template<typename ...SYSTEM_CTYPES>
    bool BaseSystem<SYSTEM_CTYPES...>::addNewComponent(componentTag_t const & tag, BaseComponent* newComponent)
    {
    	if(processNewComponent<0, SYSTEM_CTYPES...>(tag, newComponent/*, Other thing ?*/))
    	{
    		return true;
    	}
     
    	return false;
    }
     
    template<typename ...SYSTEM_CTYPES>
    template<std::size_t PROCESS_ID, typename CTYPE, typename ...OTHER_CTYPES>
    bool BaseSystem<SYSTEM_CTYPES...>::processNewComponent(componentTag_t const & tag, BaseComponent* newComponent/*, Other thing ?*/)
    {
            DBG_ASSERT(CTYPE::signature != BaseComponent::signature)
    	DBG_ASSERT(tag != BaseComponent::signature)
     
    	if(CTYPE::signature == tag)
    	{
    		// do something using PROCESS_ID ( maybe store the new component in a tuple or a vector thanks to PROCESS_ID ?)
    		return true;
    	}
    	else
    	{
    		return processNewComponent<PROCESS_ID+1, OTHER_CTYPES...>(tag, newComponent);
    	}
    }
     
    template<typename ...SYSTEM_CTYPES>
    template<std::size_t PROCESS_ID>
    bool BaseSystem<SYSTEM_CTYPES...>::processNewComponent(componentTag_t const & tag, BaseComponent* newComponent/*, Other thing ?*/)
    {
    	// same as before but used for termination. In this case, no match occurred
    	// in this case, just return false...
    	return false;
    }

    On constate donc, dans ce fonctionnement, que le nouveau composant est passé en paramètre de la méthode addNewComponent(). Il est donc important de pouvoir récupérer ici n'importe quel type de composant. Cependant, idiot que je suis, je me demande si je ne peux pas passer ce type en template + déclaration implicite.... Cela devrait fonctionner. A tester.
    edit : dans le code ci-dessus, j'ai pris la liberté de passer en paramètre aussi le tag. Cette implémentation implique, en fait, que la signature du composant soit récupérée avant d'entrer dans la fonction. Néanmoins, le problème reste le même dans le sens où je vais devoir extraire cette signature à un moment ou un autre. Cependant, je peux imaginer que ce tag est fourni / stocké quelque-part, en dehors du composant lui-même, lors de l'instanciation de l'objet... A voir, cela fait parti d'un axe de recherche... En procédant de cette manière, je devrais pouvoir me dépatouiller d'une manière ou une autre...


    Comme demandé : "pourquoi ne pas donner directement le/les bon composants au moment de l'ajout au système ?" J'y ai pensé aussi... Néanmoins, que ce soit le manager ou le système, il faudra bien que l'un ou l'autre se colle à cette tâche. De plus, il est tellement plus simple de dire au manager :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    for(auto s:m_system)
    {
    	s.addNewComponent(&simpleNewComponent);
    }
    de cette manière, les systèmes intéressés récupèrent le pointeur, pas les autres.

    Enfin, voici donc comment j’imagine la création d'un système (final) :


    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
    class WonderfullSystem: BaseSystem<BobComponent, AliceComponent>
    {
    public:
     
    	virtual void update() override final;
    	{
    		for(auto a:m_componentTuples)
    		auto currentBob = std::get<BobComponent>(a);
    		auto currentAlice = std::get<AliceComponent>(a);
     
    		// make Bob and Alice do whatever you want with... 
    	}
    };
     
     
    Manager myManager;
    myManager.addSystem(WonderfullSystem{});

    Concernant les systèmes, bien qu'il n'y ait ici que le squelette du code final, on s’aperçoit que toute l'implémentation est triviale de A à Z (c'est peut être trop light justement ?), et la création d'un nouveau système est on ne peut plus directe et explicite.


    Tout ça pour en arriver au fait que, la classe BaseSystem fait apparaitre : CTYPE::signatureCTYPE représente une des potentielles multiples classes qui définissent justement l'essence de notre système. D'où l'importance que chaque composant ait un identifier unique par type (d'où le static constexpr std::size_t signature). En parallèle, lorsque l'on ajoute donc de nouvelles valeurs pour un composant donné, a un système, ce composant est passé en paramètre, d'où l'importance que chaque composant puisse se substituer à un composant neutre (le BaseComponent).


    En ce qui concerne les solutions proposés, effectivement, je ne me lancerais pas dans un switch() ^^ c'est en très grande partie pour éviter ça que je cherche une solution. Cependant, qu'il s'agisse du type, d'une chaîne de caractère, un hash ou un ticket de loto, peu importe la manière, je dois pouvoir être capable d'identifier clairement le type d'un objet afin de réaliser des comparaisons (!= / == / || / && etc..).

    De ce que j'ai pu comprendre du RTTI de la stl, l'utiliser quand on fait un ecs, c'est un peu comme construire une formule1 en utilisant du plomb au lieu du carbone... Je n'utiliserais donc pas de std::typeid ici. Cependant, je viendrais corriger ici un point qui me semble important : je ne souhaite pas que les enfants connaissent le type de leurs parents, ils n'en ont strictement rien à faire. C'est justement tout l'inverse que je souhaite faire : pouvoir récupérer, depuis le parent, le type de l'enfant auquel il est rattaché.

    Pour ça, effectivement, le CRTP peut sembler intéressant aux premiers abords ; cependant, cela implique que la classe parente est donc... un template. Ce que je ne veux surtout pas dans le sens où la classe BaseComponent a vocation à être substituée par ses enfants.


    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
    struct Base
    {
    public:
    	static constexpr std::size_t tag{0};
    };
     
    struct A:Base
    {
    	static constexpr std::size_t tag{1};
    };
     
    struct B:Base
    {
    	static constexpr std::size_t tag{2};
    };
     
     
    int main()
    {
     
    	std::vector<Base> m_vec;
     
    	m_vec.push_back(A{});
    	m_vec.push_back(B{});
    	m_vec.push_back(B{});
    	m_vec.push_back(Base{});
     
    	for(auto v:m_vec)
    	{
    	    std::cout << v.tag << std::endl;
    	}
     
     
    	return 0;
    }
    et le retour : "0 0 0 0" --> Que les id de la structure "Base" !!! A vrai dire, je m'en fiche que la structue "Base" ait un identifiant (en vrai) mais si je le lui enlève, le bout de code ci-dessus ne compile plus...
    Le retour souhaité ici est " 1 2 2 0" ...

    Je vais continuer à me triturer les méninges autour de ça... Je vais bien finir par trouver une solution.

    Merci à vous !

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

Discussions similaires

  1. Héritage initialisation membre const
    Par themadmax dans le forum C++
    Réponses: 7
    Dernier message: 26/05/2011, 15h31
  2. Pointeur de fonction membre et héritage
    Par Caduchon dans le forum Langage
    Réponses: 6
    Dernier message: 25/03/2011, 12h02
  3. [POO] Héritage : Surcharge d'un membre statique parent
    Par Nullos Oracle dans le forum Langage
    Réponses: 7
    Dernier message: 11/09/2007, 18h39
  4. Réponses: 16
    Dernier message: 17/03/2007, 17h31
  5. [POO] Pointeur sur fonction membre et héritage
    Par MrDuChnok dans le forum C++
    Réponses: 9
    Dernier message: 20/07/2006, 17h19

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