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 :

[libraries] problemes avec le polymorphisme


Sujet :

Langage C++

  1. #1
    Membre expérimenté
    Profil pro
    Inscrit en
    Juillet 2008
    Messages
    1 562
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2008
    Messages : 1 562
    Points : 1 313
    Points
    1 313
    Par défaut [libraries] problemes avec le polymorphisme
    Bonjour

    je rencontre un problème étonnant ...

    voici le principe que j'ai, avec 3 logiciels :
    • une librairie static qui contient
      • un interface IThread avec deux méthodes virtuelles pures
        • start
        • stop
      • Thread qui dérive de IThread et implémente les deux méthodes (start et stop)
    • une librairie shared qui contient un objet Alpha qui dérive Thread
    • un logiciel exécutable Main qui charge avec dlopen la librairie shared et instancie l'objet Alpha sous sa forme IThread

    (il va de soit que toutes ces librairies sont référencées et linkées correctement pour que cela puisse se compiler et s’exécuter sans problème)

    si j'ai redéfini les méthodes start et stop dans l'objet Alpha comme ceci
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    virtual bool start() {
    		printf("[libYYYY::Alpha] : start \n");
    		return Thread::start();
    	}
    	virtual bool stop() {
    		printf("[libYYYY::Alpha] : stop \n");
    		return true;
    	}
    et que dans Main j'appel le start() sur IThread tout marche bien

    si par contre je commente la fonction start() et que je ne change pas le code d'appel de Main
    ça appel le stop() ... et pas le start() du parent c'est a dire celui du Thread, comme s'il ne pouvait résoudre le polymorphisme ...

    si vous aviez quelques pistes ça intéresserait beaucoup ....

    Merci
    IKEAS : Finalement je crois que c'est dans ses faiblesses que l'on y trouve a la fois de la force et a la fois de la richesse...
    ----------------------------------------------------
    Si vous avez du taf en wpf & design d'application sympa, contactez moi !!!!
    http://ultimatecorp.eu/wpf/

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

    Informations professionnelles :
    Activité : aucun

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

    J'aurais tendance à dire que tu n'as simplement pas fait afficher quoi que ce soit dans la fonction start de IThread...

    Si tu as une fonction virtuelle -- pour laquelle tu donne une implémentation -- dans la classe de base et que tu ne redéfinis pas le comportement de cette fonction dans la classe dérivée, il est tout à fait normal que ce soit le comportement défini pour la classe de base qui soit utilisé, même si tu appelles cette fonction au départ d'un (pointeur / (e) référence) connu comme étant du type de base (IThread dans le cas présent) mais faisant référence à un objet de type dérivé (en l'occurrence Alpha) .

    S'il n'y a pas d'affichage prévu dans l'implémentation de la fonction au niveau de la classe de base, tu ne verras tout simplement pas que c'est ce comportement là qui est réellement invoqué et, si tu provoque un affichage dans l'implémentation spécifique à un type dérivé d'une fonction qui sera appelé juste après (ou peu s'en faut), tu peux avoir l'impression que seule "la fonction appelée après" est appelée

    Mais, de manière générale, il n'est pas bon de provoquer une sortie (avec printf std::cout ou std::cerr) pour le débuggage dans les fonctions qui ne sont pas sensées afficher quoi que ce soit : si tu veux savoir ce qui est réellement effectué, tu dois utiliser le débuggeur
    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 expérimenté
    Profil pro
    Inscrit en
    Juillet 2008
    Messages
    1 562
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2008
    Messages : 1 562
    Points : 1 313
    Points
    1 313
    Par défaut
    pour info dans toutes les fonctions j'ai collé un cout ...
    ceci étant ça explique pas vraiment pourquoi quand je lance le start il passe dans le stop !!! (si le start n'est pas défini explicitement dans Alpha) et je me doute bien qu'avec le polymorphisme il devrait normalement aller dans le start de Thread ....

    et effectivement avec le debugger quand je fait alpha->start(); .... ca va dans le stop() lol

    maintenant j'ai même pire dans un autre bout de code : si je met le start avant le stop
    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
    virtual bool start() {
    		Log::i(LCN, "start");
    		cout << "[" << LCN << "] " << "start" << endl;
    		Thread::start();
    		return true;
    	}
     
    	virtual bool stop() {
    		Log::i(LCN, "stop");
    		cout << "[" << LCN << "] " << "stop" << endl;
    		Thread::stop();
    		return true;
    	}
    il passe dans le stop
    pour le faire passer dans le start il faut que je fasse
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    	virtual bool stop() {
    		Log::i(LCN, "stop");
    		cout << "[" << LCN << "] " << "stop" << endl;
    		Thread::stop();
    		return true;
    	}
     
    	virtual bool start() {
    		Log::i(LCN, "start");
    		cout << "[" << LCN << "] " << "start" << endl;
    		Thread::start();
    		return true;
    	}
    je me demande si le compilateur serait pas carrement dans les choux !!!
    IKEAS : Finalement je crois que c'est dans ses faiblesses que l'on y trouve a la fois de la force et a la fois de la richesse...
    ----------------------------------------------------
    Si vous avez du taf en wpf & design d'application sympa, contactez moi !!!!
    http://ultimatecorp.eu/wpf/

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 612
    Points : 30 612
    Points
    30 612
    Par défaut
    Plutôt que de ne nous donner que des portions de code, pourrais tu s'il te plait nous donner le contenu intégral
    • du fichier d'en-tête dans lequel tu as défini la classe de base (thread.h/.hpp?)
    • du fichier d'implémentation des fonctions de la classe de base (thread.cpp?)
    • du fichier d'en-tête dans lequel tu as défini la classe Alpha Alpha.h/.hpp?)
    • du fichier d'implémentation des fonctions de la classe Alpha (Alpha.cpp?)


    et nous indiquer un code minimal compilable qui puisse reproduire ton problème

    A mon avis, si tu ne profites pas du polymorphisme, c'est très vraisemblablement parce que tu transmet un objet de type dérivé (Alpha) à une fonction qui attend un objet de type IThread qui devrait lui être transmis par valeur. Or, pour profiter du polymorphisme, il faut passer par l'utilisation des pointeurs ou, plus sécurisant du fait de la garantie de non nullité (ou, si tu préfères, de la garantie d'existence de la variable référencée) par référence.

    En effet, lorsqu'un paramètre de fonction est passé par valeur au lieu d'être passé par référence (éventuellement constante) ou par pointeur, il y a copie de l'élément transmis, mais il souffre du phénomène de slicing qui fait que seule la partie relative au type de base est copiée (et, du coup, c'est effectivement un objet du type de base et non un objet du type dérivé que la fonction reçoit).

    Pour éviter cela, il faut veiller à respecter la sémantique d'entité des classes intervenant dans une hiérarchie de classes en veillant à les rendre non copiables et non affectables (différentes possibilités sont offertes, en fonction de la norme C++ utilisée pour le projet ), ce qui aura pour effet de provoquer une erreur de compilation (ou, dans le pire des pire des cas, d'édition des liens) si tu essayes de faire appel à une fonction qui attend un objet du type de base transmis par valeur
    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

  5. #5
    Membre expérimenté
    Profil pro
    Inscrit en
    Juillet 2008
    Messages
    1 562
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2008
    Messages : 1 562
    Points : 1 313
    Points
    1 313
    Par défaut
    en fait j'ai trouvé d'ou cela venait
    je faisais des cast (IThread *) et il fallait faire des dynamic_cast<IThread *>()
    c'est pour cela que je perdais la table des fonctions virtuelles

    ceci étant c++ aurait pu évoluer pour éviter ce genre de prob !!!! d'autant que je ne vois pas l'interet de transformer un object X en sont parent juste pour appeler une methode en directe de celui et encore faut pas qu'elle soit virtuelle
    IKEAS : Finalement je crois que c'est dans ses faiblesses que l'on y trouve a la fois de la force et a la fois de la richesse...
    ----------------------------------------------------
    Si vous avez du taf en wpf & design d'application sympa, contactez moi !!!!
    http://ultimatecorp.eu/wpf/

  6. #6
    Rédacteur/Modérateur


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

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 113
    Points : 32 960
    Points
    32 960
    Billets dans le blog
    4
    Par défaut
    Si tu es sûr que le cast est possible, un static_cast suffit.
    Le cast C-style est un équivalent d'un reinterpret_cast. Et c'est généralement pas le genre de cast qu'on emploie au quotidien.
    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.

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 612
    Points : 30 612
    Points
    30 612
    Par défaut
    Citation Envoyé par ikeas Voir le message
    en fait j'ai trouvé d'ou cela venait
    je faisais des cast (IThread *) et il fallait faire des dynamic_cast<IThread *>()
    c'est pour cela que je perdais la table des fonctions virtuelles

    ceci étant c++ aurait pu évoluer pour éviter ce genre de prob !!!! d'autant que je ne vois pas l'interet de transformer un object X en sont parent juste pour appeler une methode en directe de celui et encore faut pas qu'elle soit virtuelle
    C'est surtout que tu n'as absolument pas besoin de faire le moindre cast d'un objet de type dérivé pour le transmettre à une fonction qui attend un paramètre du type de base!!!

    Un petit code d'exemple pour t'en convaincre:
    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
    // dans des fichiers .h / .hpp séparés, le plus souvent
    class Base{
        public:
            virtual ~Base();
            virtual void foo() const;
    };
    class Derivee1 : public Base{
        public:
             /* override est spécifique à C++11, tu peux le retirer si tu utilises
              * une norme antérieure
              */
            void foo() const override;
    };
    class Derivee2: public Base{
        public:
             /* override est spécifique à C++11, tu peux le retirer si tu utilises
              * une norme antérieure
              */
            void foo() const override;
    };
    //dans des fichier .cpp séparés le plus souvent
    #include <iostream>
    Base::~Base(){
    }
    void Base::foo() const{
        std::cout<<"Appel de Base::foo\n";
    }
     
    void Derivee1::foo() const{
        std::cout<<"Appel de Derivee1::foo\n";
    }
     
    void Derivee2::foo() const{
        std::cout<<"Appel de Derivee2::foo\n"
                      <<"avec appel de Base::foo :";
        Base::foo();
    }
    /* une fonction qui prend une référence constante sur le type de base
     */
    void bar(Base const & b){
        b.foo(); /* appellera Base::foo si le type réel de la variable transmise pour b
                  * est Base,  Derivee1::foo si le type réel de la variable transmise pour b
                  * est Derivee1 et Derivee2::foo si c'est Derivee2
                  */
    }
    int main(){
        Base b;
        bar(b); // affiche Appel de Base::foo
        Derivee1 d1;
        bar(d1); // affiche "appel de Derivee1::foo"
        Derivee2 d2;
        bar(d2); /* affiche ""Appel de Derivee2::foo
                  * avec appel de Base::foo : Appel de Base::foo
                  */
        return 0;
    }
    Mais, comme je présume que tu seras plutôt dans une situation dans laquelle tu auras un tableau d'objet polymorphes connus comme étant de type Base, on peut modifier la fonction main pour qu'elle prenne la forme (en C++11) de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    #include <vector>
    #include <memory>
    int main(){
        std::vector<std::unique_ptr<Base>> tab;
        tab.emplace_back(new Base);
        tab.emplace_back(new Derivee1);
        tab.emplace_back(new Derivee2);
        for(auto const & it : tab){
            bar(*(it.get()));
        }
        return 0;
    }
    Et, si tu ne disposes pas de C++11, cela pourrait prendre une forme proche de
    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
     
    #include <vector>
    int main(){
        std::vector<Base *> tab;
        tab.push_back(new Base);
        tab.push_back(new Derivee1);
        tab.push_back(new Derivee2);
        for(size_t i = 0;i<tab.size();++i){
            bar(*(tab[i]));
        }
        /* n'oublions pas de libérer la mémoire allouée aux pointeurs
         */
        for(size_t i = 0;i<tab.size();++i){
            delete tab[i];
        }
        return 0;
    }
    Ces trois versions de la fonction main provoqueront exactement la même sortie qui ressemblera à
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    Appel de Base::foo
    appel de Derivee1::foo
    Appel de Derivee2::foo
    avec appel de Base::foo : Appel de Base::foo
    Magique, non
    [EDIT]La seule chose que tu aies à faire, c'est de maintenir la variable connue comme étant du type de base sous la forme d'un pointeur (de préférence intelligent) pour lequel tu auras eu recours à l'allocation dynamique de la mémoire ou d'une référence (éventuellement constante) sur une instance du type dérivé dont la durée de vie dépasse celle de la référence. Voir, c'est toujours mieux, sous la forme d'une instance du type dérivé, si tu connais le type réel utilisé à la compilation (et que tu ne dois donc pas choisir le type de la variable à l'exécution )
    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

  8. #8
    Membre expérimenté
    Profil pro
    Inscrit en
    Juillet 2008
    Messages
    1 562
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2008
    Messages : 1 562
    Points : 1 313
    Points
    1 313
    Par défaut
    ben la probleme c'est que je ne suis pas en c++11
    je suis en gcc 4.4.6
    en plus dans le segment de code que j’exécute l'objet Alpha (par exemple) n'est pas vraiment connu puisqu'il est dans une shared library

    j'utilisais une factory qui me crée l'object sous forme d'interface IObject par exemple pour Alpha
    mais si je colle pas le dynamic_cast ca passe pas a la compilation ....

    si tu veux je peux te filer un code qui permet de voir comment c'est codé
    IKEAS : Finalement je crois que c'est dans ses faiblesses que l'on y trouve a la fois de la force et a la fois de la richesse...
    ----------------------------------------------------
    Si vous avez du taf en wpf & design d'application sympa, contactez moi !!!!
    http://ultimatecorp.eu/wpf/

  9. #9
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 187
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

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

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 187
    Points : 17 135
    Points
    17 135
    Par défaut
    Oui, on veut bien.
    Merci!
    Mes principes de bases du codeur qui veut pouvoir dormir:
    • Une variable de moins est une source d'erreur en moins.
    • Un pointeur de moins est une montagne d'erreurs en moins.
    • Un copier-coller, ça doit se justifier... Deux, c'est un de trop.
    • jamais signifie "sauf si j'ai passé trois jours à prouver que je peux".
    • La plus sotte des questions est celle qu'on ne pose pas.
    Pour faire des graphes, essayez yEd.
    le ter nel est le titre porté par un de mes personnages de jeu de rôle

  10. #10
    Membre expérimenté
    Profil pro
    Inscrit en
    Juillet 2008
    Messages
    1 562
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2008
    Messages : 1 562
    Points : 1 313
    Points
    1 313
    Par défaut
    voila pour enregister mes objects dans un segment global j'utilise un template

    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
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    /********************************************************
     * Libs_base.hpp
     *
     *  Created on: Sep 18, 2014
     *      Author: dev
     ********************************************************/
    #pragma once
     
    #include <iostream>
    #include <typeinfo>
    #include <vector>
    #include <string>
    #include <map>
    #include <algorithm>
     
    using namespace std;
     
    #include "IObject.hpp"
    #include "Sysutils.hpp"
    #include "IToString.hpp"
    #include "Log.hpp"
     
    namespace cy {
     
    // abstract class for error
    struct Abstract {
    	virtual void foo() = 0;
    	virtual ~Abstract() {
    	}
    };
    template<typename T> struct error {
    	static void set() {
    		new T();
    	}
    };
     
    /*
     *  constructeurs
     */
    class baseConstructor {
    public:
    	virtual IObject *create() = 0;
    	virtual ~baseConstructor() {
    	}
    };
    template<typename Type>
    class constructor: public baseConstructor {
    public:
    	virtual IObject *create() {
    		return dynamic_cast<IObject*>(new Type());
    	}
    };
     
    typedef map<string, baseConstructor *> mapSBC;
     
    /*
     * Class static de references
     *
     */
    template<class Interface>
    class Referencies: TIToString<Referencies<Interface>> {
    private:
    	Referencies() {
    	}
    	class Initializer {
    	public:
    		Initializer() {
    			Log::i("Referencies", "Initializer : constructor");
    			//cout << "[Referencies] static constructor" << endl;
    			////added = NULL;
    		}
    	};
    	//friend class Initializer;
    	static Initializer init;
     
    	static void addedFunc(string added) {
    	}
     
    public:
    	static void initialize() {
    		//cout << "[Referencies] initialize<" << type_name<Interface>() << ">"
    		//		<< endl;
    		ptrlist = new mapSBC();
    		// a mettre obligatoirement sinon ca ne decharge pas la librairie (une des deux lignes lignes ci dessous)
    		//added = addedFunc;
    		added = NULL;
    	}
    	static void clear() {
    		//cout << "[Referencies] CLEAR";
    		if (ptrlist->size() == 0) {
    			//cout << " EMPTY" << endl;
    			return;
    		}
    		//cout << endl;
    		for (mapSBC::iterator it = ptrlist->begin(); it != ptrlist->end();
    				++it) {
    			if (it->second != NULL) {
    //				cout << " - delete " << it->first << " = " << it->second
    //						<< endl;
    				delete it->second;
    			}
    		}
    		ptrlist->clear();
    	}
    	static void add(string className, baseConstructor *c) {
    //		cout << "[Referencies] ADD < " << type_name<Interface>().c_str()
    //				<< "> = " << className.c_str() << " constructor  = " << c
    //				<< endl;
    		Log::i("Referencies", "Add<%s> = %s", type_name<Interface>().c_str(),
    				className.c_str());
    		//Log::i("Referencies", "Add : added = %d", added);
    		//list.insert(std::pair<string,baseConstructor *>(className, (baseConstructor *)NULL));
    //		if(ptrlist == NULL)
    //			ptrlist = new mapSBC();
    		(*ptrlist)[className] = c;
    		if (added != NULL) {
    			//Log::i("Referencies", "Add : raise added");
    			added(className);
    		}
    	}
    	static void remove(string className) {
    //		cout << "[Referencies] REMOVE <" << type_name<Interface>().c_str()
    //				<< "> = " << className.c_str() << " YYY" << endl;
    		Log::i("Referencies", "Remove<%s> = %s", type_name<Interface>().c_str(),
    				className.c_str());
    		mapSBC::iterator itx = ptrlist->find(className);
    		if (itx == ptrlist->end())
    			return;
    		if (itx->second != NULL)
    			delete itx->second;
    		ptrlist->erase(itx);
    	}
    	static void setNotification(notiFyAddedEventHandler a) {
    		Log::i("Referencies", "setNotification : for %s",
    				type_name<Interface>());
    		added = a;
    		Log::i("Referencies", "setNotification : added = %d", added);
    	}
    	static vector<string> getClass() {
    		vector<string> vec;
    		for (mapSBC::iterator it = ptrlist->begin(); it != ptrlist->end(); ++it)
    			vec.push_back((*it).first);
    		return vec;
    	}
    	static bool exist(string className) {
    		mapSBC::iterator itx = ptrlist->find(className);
    		return (itx != ptrlist->end());
    	}
    	static Interface* newInstance(string className) {
    		mapSBC::iterator itx = ptrlist->find(className);
    		if (itx == ptrlist->end())
    			return NULL;
    		try {
    			Interface* i = dynamic_cast<Interface*>((*ptrlist)[className]->create());
    			return i;
    		} catch (...) {
    			return NULL;
    		}
    	}
    	static void show() {
    		cout << "[Referencies] show<" << type_name<Interface>() << ">";
    		if (ptrlist->size() == 0) {
    			cout << " EMPTY " << endl;
    			return;
    		}
    		cout << endl;
    		try {
    			for (mapSBC::iterator it = ptrlist->begin(); it != ptrlist->end();
    					++it) {
    				cout << " - " << (*it).first << endl;
    			}
    		} catch (...) {
    		}
    	}
    	virtual string toString() {
    		string ret = "";
    		for (mapSBC::iterator it = ptrlist->begin(); it != ptrlist->end();
    				++it) {
    			ret += (*it).first + " ";
    		}
    		return ret;
    	}
    	static notiFyAddedEventHandler added;
    //static int test;
    private:
    	//static map<string, baseConstructor *> list;
    	static map<string, baseConstructor *> *ptrlist;
    };
     
    /* membre static de Referencies */
    //template<class Interface>
    //map<string, baseConstructor *> Referencies<Interface>::list;
    template<class Interface>
    mapSBC *Referencies<Interface>::ptrlist;
     
    template<class Interface>
    notiFyAddedEventHandler Referencies<Interface>::added = NULL;
     
    //template<class Interface>
    //Referencies<Interface>::Initializer Referencies<Interface>::init;
     
    /*
     *
     *
     */
    template<class Interface, class Type, bool B = __is_base_of(Interface, Type)>
    class AddReferency {
    public:
    	AddReferency() {
    //		cout << "[AddReferency] ADD <" << type_name<Interface>() << "> = "
    //				<< type_name<Type>()
    //				<< "******************************************* " << endl;
    		Log::i("AddReferency", "Add<%s> = %s", type_name<Interface>().c_str(),
    				type_name<Type>().c_str());
    		Referencies<Interface>::add(type_name<Type>(), new constructor<Type>());
    //		Referencies<Interface>::add(type_name<Type>(), NULL);
    	}
    	~AddReferency() {
    //		cout << "[AddReferency] REMOVE <" << type_name<Interface>() << "> = "
    //				<< type_name<Type>()
    //				<< "***************************************" << endl;
    		Log::i("AddReferency", "Remove<%s> = %s",
    				type_name<Interface>().c_str(), type_name<Type>().c_str());
    		Referencies<Interface>::remove(type_name<Type>());
    	}
    };
     
    template<class Interface, class Type>
    class AddReferency<Interface, Type, 0> {
    public:
    	AddReferency() {
    		//cout << "  ADD probleme" << endl;
    		Log::i("AddReferency", "Add Error<%s> = %s",
    				type_name<Interface>().c_str(), type_name<Type>().c_str());
    		error<Abstract>::set();
    	}
    	~AddReferency() {
    	}
    };
     
    } // end namespace
    et dans ma shared library j'ai le code suivant par exemple
    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
    class YAlpha: public IObjectType<YAlpha>, public Thread {
    private:
    	string message;
    	int time;
    	YBeta *ybeta;
    public:
    	YAlpha() :
    			message(""), time(0), ybeta(NULL) {
    		printf("[libYYYY::YAlpha] : Constructeur\n");
    	}
    	 ~YAlpha() {
    		printf("[libYYYY::YAlpha] : Destructeur\n");
    	}
    protected:
    	virtual void exec() {
    		printf("[libYYYY::YAlpha] : exec \n");
    		if (this->ybeta != NULL) {
    			while (true) {
    				this->ybeta->message("[YAlpha] THREAD > " + this->message);
    				usleep(time * 1000000);
    			}
    		} else
    			cout << "ybeta non initialisé" << endl;
    	}
    	;
    public:
    //	virtual bool start() {
    //		printf("[libYYYY::YAlpha] : start \n");
    //		return Thread::start();
    //	}
    	virtual bool stop() {
    		printf("[libYYYY::YAlpha] : stop \n");
    		return true;
    	}
     
    	virtual bool setParameters(ParameterList& params) {
    		printf("[libYYYY::YAlpha] : setParameters \n");
    		printf("{\n");
    		cout << params.toString() << endl;
    		printf("}\n");
    		{
    			ParamValue& pv = params.get<ParamValue>("message");
    			if (!pv.isNull) {
    				this->message = pv.value;
    			}
    		}
    		{
    			ParamValue& pv = params.get<ParamValue>("temps");
    			if (!pv.isNull) {
    				this->time = stoi(pv.value);
    			}
    		}
    		{
    			ParamRef& pr = params.get<ParamRef>("ref_beta");
    			if (!pr.isNull) {
    				this->ybeta = dynamic_cast<YBeta*>(pr.value);
    				this->ybeta->message(
    						"Message transmis par YAlpha > " + this->message);
    			}
    		}
    		return true;
    	}
    };
    avec pour le referencement automatique
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    namespace {
    AddReferency<IObject, YAlpha> _yalpha;
    AddReferency<IThread, YAlpha> _yalpha2;
     
    }
    bref quand je veux instancier un object apres avoir chargé la librarie 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
    15
     
    Referencies<IObject>::initialize();
    Referencies<IThread>::initialize();
     
    	LibraryXX lib;
    			cout << endl << "LOAD " << endl;
    			lib.loadLibrary(
    					(char*) "/usr/local/bin/sharedLibraries/libDrivers.so");
    			cout << endl;
    			Referencies<IObject>::show();
    			Referencies<IThread>::show();
     
    			cout << endl;
    			IThread *it = Referencies<IThread>::newInstance("cy::YAplha");
    			IObject *io = dynamic_cast<IObject*>(it);
    c'est la que j'avais le probleme avec le cast ....
    avec la fonction newInstance
    IKEAS : Finalement je crois que c'est dans ses faiblesses que l'on y trouve a la fois de la force et a la fois de la richesse...
    ----------------------------------------------------
    Si vous avez du taf en wpf & design d'application sympa, contactez moi !!!!
    http://ultimatecorp.eu/wpf/

  11. #11
    Rédacteur/Modérateur


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

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 113
    Points : 32 960
    Points
    32 960
    Billets dans le blog
    4
    Par défaut
    J'ai l'impression que le polymorphisme n'est pas maitrisé..
    Autant de dynamic_cast c'est du jamais vu.

    Rien que cette ligne est déjà suspecte et ne devrait pas exister
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    return dynamic_cast<IObject*>(new Type());
    Pourquoi un dynamic_cast ?! Quel intérêt ??
    Avec ton dynamic_cast tu te retrouves à pouvoir créer n'importe quoi, tenter un cast et retourner NULL.. Avec une fuite mémoire au passage.
    Tu vires ce cast et si tu essayes d'appeler cette fonction avec un truc qui n'a rien à voir avec IObject alors ça plante à la compilation. Ca ce serait un code sur.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    template<typename T> struct error {
    	static void set() {
    		new T();
    	}
    };
    Ca s'appelle pas une fuite mémoire ça par hasard ?

    Vu qu'il y a un #pragma once je suppose qu'on est dans un header.
    Et en plus il y a d'autres includes derrière ce using.. ou comment ouvrir la porte à un bordel monstre.

    Quel est le lien entre IThread et IObject ? Si la réponse est aucun, alors un cast est clairement non-avenu. Sauf à vouloir jouer aux apprentis sorciers et espérer que ça passe sans tout exploser.
    L'ensemble de ton code s'apparente à un conglomérat de mauvaises pratiques et worst cases scenarios d'utilisation du polymorphisme, des cast et interface/mot-clé virtual.
    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.

  12. #12
    Membre expérimenté
    Profil pro
    Inscrit en
    Juillet 2008
    Messages
    1 562
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2008
    Messages : 1 562
    Points : 1 313
    Points
    1 313
    Par défaut
    J'ai l'impression que le polymorphisme n'est pas maitrisé..
    no comment

    Pourquoi un dynamic_cast ?! Quel intérêt ??
    justement par ce que le compilateur refuse de compiler (je suis pas en c++11), j'ai essayé en Visual studio ça passe sans ....

    template<typename T> struct error {.....
    la structure error sert a avoir une erreur de compilation quand tu fais un AddRefency avec un interface qui n'est pas implémenté dans la classe... en utilisant la spécialisation de template avec le trait (__is_base_of(Interface, Type))
    j'aurais bien aimé trouver une autre solution pour que ça coince a la compile mais je n'en ai pas trouvé, si tu en as je suis preneur

    Quel est le lien entre IThread et IObject ?
    on est dans un cadre de liaison faible dans ce logiciel ou tout objet est un IObject .... personne ne connait personne, c'est le principe des framework (enfin en java, c# etc...) bref comme c++ a pas de classe de base, on refait ce monde .... donc a un moment quand un objet reçois une référence il doit pouvoir la caster dans un interface XXX qu'il connait (évidement comme la reflection n'existe pas non plus en c++, c'est pas du gâteau) bref il faut bien trouver des solutions acceptables

    J'ai l'impression que le polymorphisme n'est pas maitrisé..
    finalement je vais commenter .... je donne des cours objet (stratégies) et design pattern, mais j'ai sans doute encore a apprendre sur le polymorphisme ... ceci étant je fais des choses en java, c# très très abstraite et ça passe
    et s'il n'y avait pas autant de problème avec un cast standard je t'assure que j'aurais même pas posé la question (je te rappel que sur c++11 il n'y a aucun soucis, c'est donc que je ne suis sans doute pas le seul a avoir eu cela)

    Conclusion : (enfin la mienne )
    ça serait sympa que ceux qui développent le langage c++ se rapprochent des standards et possibilités des autres langages ...
    IKEAS : Finalement je crois que c'est dans ses faiblesses que l'on y trouve a la fois de la force et a la fois de la richesse...
    ----------------------------------------------------
    Si vous avez du taf en wpf & design d'application sympa, contactez moi !!!!
    http://ultimatecorp.eu/wpf/

  13. #13
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 518
    Points
    41 518
    Par défaut
    justement par ce que le compilateur refuse de compiler
    Allons, qui serait assez idiot pour mettre un cast pour que le compilo ferme sa gueule sans vraiment corriger l'erreur?©
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  14. #14
    Membre expérimenté
    Profil pro
    Inscrit en
    Juillet 2008
    Messages
    1 562
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2008
    Messages : 1 562
    Points : 1 313
    Points
    1 313
    Par défaut
    je veux pas polémiquer
    mais bon pour simplifier le baseConstructor ne sait faire que des IObject (fonction create)
    or dans le newInstance on renvoi des éléments sur le template Interface*

    donc comment faire sans caster ??? si vous avez une solution, c'est mieux que de dire qu'il n'y a que les idiots qui ne font que cela

    maintenant j'attend qu'un mec intelligent me propose une solution pour faire ce que je fais (qui est de la petite reflection en c++) si tu regarde les lib qui existent boost, camp et cppreflect, ils ne font que cela caster dans tous les sens, j'ai pas forcement réinventé le monde je m'en suis inspiré ...

    et pour info je suis sur que le cast va passer puisque mon objet est forcement du type Interface (c'est contrôlé par la spécialisation du Template) donc a l’exécution ça passe ...
    IKEAS : Finalement je crois que c'est dans ses faiblesses que l'on y trouve a la fois de la force et a la fois de la richesse...
    ----------------------------------------------------
    Si vous avez du taf en wpf & design d'application sympa, contactez moi !!!!
    http://ultimatecorp.eu/wpf/

  15. #15
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 518
    Points
    41 518
    Par défaut
    Ton interface n'hérite-t-elle pas de IObject?
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  16. #16
    Rédacteur/Modérateur


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

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 113
    Points : 32 960
    Points
    32 960
    Billets dans le blog
    4
    Par défaut
    Citation Envoyé par ikeas Voir le message
    et pour info je suis sur que le cast va passer puisque mon objet est forcement du type Interface (c'est contrôlé par la spécialisation du Template) donc a l’exécution ça passe ...
    Pourtant tu dis que ça plante à la compil sinon. Si ça c'est pas un signe..

    Citation Envoyé par ikeas Voir le message
    maintenant j'attend qu'un mec intelligent me propose une solution pour faire ce que je fais (qui est de la petite reflection en c++) si tu regarde les lib qui existent boost, camp et cppreflect, ils ne font que cela caster dans tous les sens, j'ai pas forcement réinventé le monde je m'en suis inspiré ...
    Oui ils le font, mais ils ont une vraie classe de base et font du vrai héritage.

    Citation Envoyé par ikeas Voir le message
    mais bon pour simplifier le baseConstructor ne sait faire que des IObject (fonction create)
    or dans le newInstance on renvoi des éléments sur le template Interface*
    Si Interface n'hérite pas de IObject, ce que tu fais n'est pas permis, très mal et source (très) potentiel de (très) gros bugs. Dont tu as déjà fait les frais on dirait.

    Oui faire un code proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    struct Generator {
    template<class T >
    Object* Create() { return new T; }
    };
    est possible, existe et est faisable.
    Si et seulement si T et Object ont une relation d'héritage. Si T hérite de Object.
    Faire un cast de T en Object pour "que le compilo soit content", c'est même plus du niveau du hack à ce stade-là.
    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.

  17. #17
    Expert éminent sénior
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2005
    Messages
    5 068
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Février 2005
    Messages : 5 068
    Points : 12 111
    Points
    12 111
    Par défaut
    Bizarre, ça part en sucette et je ne suis pas dans l'embrouille.

    On ne va pas jouer à qui a la plus grosse, ici, clairement, on n'est pas dans les trucs bateaux qu'on ressasse aux newbies pour la 100ème fois.
    Désolé IKEAS, mais a force de voir toujours les mêmes problèmes, on fait très souvent des raccourcis.

    Je vais quand même faire une remarque sermonistique, on ne fait jamais, je dis bien jamais, de cast à la C en C++.

    Les Framework que vous citez on tous un point commun non négligeable, leurs langages ne supportent pas l'héritage multiple.

    Le dynamic_cast en C++ permet de décaler le pointeur d'objet entre les différents "this" lié à l'héritage multiple.

    Ce cast ne me choque pas, il est fait pour. C'est un corolaire de votre couplage faible.

    Pour moi, c'est l'approche naturel en C++.

    Si vous le voulez pas de ce cast, bin, il n'y en a pas besoin si vous faites de l'héritage simple.

    Sinon, pour une approche plus généraliste et donc pas C++, je vois l'approche à la COM avec une Interface à la IUnknown qui permet de récupérer une autre interface via un appel de méthode sur cette interface : QueryInterface
    http://msdn.microsoft.com/fr-fr/libr...(v=vs.85).aspx

    maintenant j'attend qu'un mec intelligent
    Désolé, j'ai pas ça sous la main.

  18. #18
    Membre expérimenté
    Profil pro
    Inscrit en
    Juillet 2008
    Messages
    1 562
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2008
    Messages : 1 562
    Points : 1 313
    Points
    1 313
    Par défaut
    Citation Envoyé par Médinoc Voir le message
    Ton interface n'hérite-t-elle pas de IObject?
    non l'interface, exprime le comportement de l'objet dans le systeme, si tu veux les objets sont dans des shared librairy et ne sont découvert par le logiciel qu'au moment de l’exécution d'ou le mécanisme AddReferency (je tente de faire de la petite reflection, comme je le ferrait en java ou en c#)

    Si vous le voulez pas de ce cast, bin, il n'y en a pas besoin si vous faites de l'héritage simple.
    c'est pas moi qui veut pas de cast, c'est bousk qui m'a dit que j’étais une "buze" a vouloir le faire (mais je prend jamais mal les choses)

    je vois l'approche à la COM avec une Interface à la IUnknown
    oui je connais COM, j'ai beaucoup pratiqué a une époque (surtout sur DirectX) , ceci étant ça cast pas mal aussi dedans

    Pourtant tu dis que ça plante à la compil sinon. Si ça c'est pas un signe..
    ce qui plante a la compile (et c'est normal) c'est lié a l'utilisation de la spécialisation de Template pour éviter justement qu'un object n'herite pas de l'interface qu'on colle par exemple
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    class A : IObject, IA {}
    class B : IObject {}
     
    AddReferency<IA,A> _a; // ca passe a la compile
    AddReferency<IA,B> _a1; // ca compile pas, normal B n’hérite pas de IA
    ce qui ne passait pas c'est la ligne suivante
    Renferencies<IA>::newInstance("A");
    et c'est normal puisque le constructeur sous j'acent ne sais produire que des IObject*
    et la newInstance doit produire des IA*

    et une dernière conclusion pour bousk (on se fache pas ok )
    je fais ca couramment en java ou en c# (et même des trucs plus velus dans ce langage)
    c'est vraiment dommage de pas pouvoir le faire simplement en c++
    (cela dit en c++11 tout marche ce qui veut bien dire que c’était la un véritable problème eheheheh)
    et pour info j'ai arrêté le hack depuis un moment

    et si Ariane 6 décolle pas ça sera de ma faute (ou qu'elle explose au décollage)

    merci bacelar pour ta pondération sympathique
    IKEAS : Finalement je crois que c'est dans ses faiblesses que l'on y trouve a la fois de la force et a la fois de la richesse...
    ----------------------------------------------------
    Si vous avez du taf en wpf & design d'application sympa, contactez moi !!!!
    http://ultimatecorp.eu/wpf/

  19. #19
    Expert éminent sénior
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2005
    Messages
    5 068
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Février 2005
    Messages : 5 068
    Points : 12 111
    Points
    12 111
    Par défaut
    Heu, moi je ne comprends pas pourquoi ça marche en C++11 sans cast.
    Déjà, je ne sais même pas depuis quand ça marche sans cast avec de l'héritage simple avec la covariance.

  20. #20
    Membre expérimenté
    Profil pro
    Inscrit en
    Juillet 2008
    Messages
    1 562
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2008
    Messages : 1 562
    Points : 1 313
    Points
    1 313
    Par défaut
    Citation Envoyé par bacelar Voir le message
    Heu, moi je ne comprends pas pourquoi ça marche en C++11 sans cast.
    Déjà, je ne sais même pas depuis quand ça marche sans cast avec de l'héritage simple avec la covariance.
    non il faut quand même un cast, mais le normal du type (IA*)
    IKEAS : Finalement je crois que c'est dans ses faiblesses que l'on y trouve a la fois de la force et a la fois de la richesse...
    ----------------------------------------------------
    Si vous avez du taf en wpf & design d'application sympa, contactez moi !!!!
    http://ultimatecorp.eu/wpf/

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 2 12 DernièreDernière

Discussions similaires

  1. Probleme avec le polymorphisme (si c'en est vraiment)
    Par Porkipic dans le forum Débuter
    Réponses: 7
    Dernier message: 16/12/2014, 01h06
  2. Réponses: 0
    Dernier message: 03/05/2010, 17h07
  3. problem avec programme polymorphisme
    Par domxaline dans le forum Débuter avec Java
    Réponses: 15
    Dernier message: 05/02/2010, 15h25
  4. Réponses: 14
    Dernier message: 09/05/2006, 15h23
  5. Problème avec la library Allegro
    Par Mat 74 dans le forum Allegro
    Réponses: 2
    Dernier message: 09/04/2006, 15h45

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