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 :

[POO] Héritage et fonction non implémentée


Sujet :

C++

  1. #1
    Membre régulier
    Profil pro
    Inscrit en
    Juin 2002
    Messages
    256
    Détails du profil
    Informations personnelles :
    Localisation : Etats-Unis

    Informations forums :
    Inscription : Juin 2002
    Messages : 256
    Points : 121
    Points
    121
    Par défaut [POO] Héritage et fonction non implémentée
    Bonjour,

    Je rencontre un problème avec l'héritage, et j'avoue qu'il me dépasse complétement. La situation est très simple : j'ai trois classes appellées PluginsManager, BaseRenderer, et Dummy. Elles sont définies comme suit :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    class PluginsManager
    {...}; //pour les dll
     
    class BaseRenderer : public PluginsManager
    {...
     
     void Hello() { MessageBox(NULL,"Hello","Ici",0);}
    };
     
     
    class Dummy : public PluginsManager
    { }; //diverses fonctions, mais PAS Hello
    Puis dans ma DLL, j'ai une fonction register prenant en argument un pointeur sur BaseRenderer :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    DLLEXPORT void register( BaseRenderer* _b )
    {
     _b->Hello();
    }
    que je lance via :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
     
     PluginsManager Pm;
     .. //Initialisations de Pm;
     
     Pm->register( new BaseRenderer() );
    Ca fonctionne parfaitement. Mais le problème, c'est que ça fonctionne tout autant si je remplace new BaseRenderer() par new Dummy(), alors que Dummy ne connaît pas du tout de méthode Hello !!!!!

    Qu'est-ce qui se passe? Pourquoi est ce que ça fonctionne encore?!

    D'une manière générale, est-ce que l'héritage est bien la technique à utiliser dans cette situation? Si non, que proposez-vous?

    Merci

    Cordialement
    OS : WinXP
    Outils : VC++ 8 (Visual Studio 2005)

  2. #2
    Membre régulier
    Profil pro
    Inscrit en
    Juin 2002
    Messages
    256
    Détails du profil
    Informations personnelles :
    Localisation : Etats-Unis

    Informations forums :
    Inscription : Juin 2002
    Messages : 256
    Points : 121
    Points
    121
    Par défaut
    En fait, je crois avoir compris.

    Lorsque je fais Pm->register( new Dummy() ), le compilateur cast automatique "vers le haut", en PluginsManager (car le prototype de ma fonction est "typedef void (*RegisterFc)(PluginsManagers* _pm)" ).
    Puis, une fois arrivé dans ma dll, il cast "vers le bas", en BaseRenderer. Cette dernière conversion ne posant aucun problème. Du coup, l'argument est bien initialisé et tout fonctionne.

    En revanche, c'est la conversion vers le haut qui peut potentiellement poser problème (ce que je voudrais, en fait).

    Donc comment pourrais-je faire pour que mon programme refuse de compiler ou au moins lance une exception si j'essaie de lancer register avec le mauvais type (pour la dll en question)?
    La seule solution que j'ai trouvé :
    - Ne plus faire dériver DummyRenderer et BaseRenderer de PluginsManager
    - changer l'argument dans le prototype de register en void*
    - caster dans la dll

    Ca "fonctionne" si les classes sont un peu évoluées et différentes (dans l'architecture). Par exemple, si ma méthode Hello tente d'écrire sur une variable que ne connait pas DummyRenderer, ca plante.
    Mais c'est vraiment pas propre... On pourrais pas avoir une petite exception quelque part qui permette de tout rattraper?
    Mieux, j'ai lu sur le forum qu'il y avait une technique utilisant l'héritage (recommandée par je-sais-plus-qui), mais je n'en sais pas plus...

    Un peu d'aide ne serait pas de refus.

    Merci

    Cordialement
    OS : WinXP
    Outils : VC++ 8 (Visual Studio 2005)

  3. #3
    Membre régulier
    Profil pro
    Inscrit en
    Juin 2002
    Messages
    256
    Détails du profil
    Informations personnelles :
    Localisation : Etats-Unis

    Informations forums :
    Inscription : Juin 2002
    Messages : 256
    Points : 121
    Points
    121
    Par défaut
    J'ai fini par trouver ce que je voulais faire. Pour la solution avec l'héritage, il fallait (du moins, ça à l'air de fonctionner) appeller register avec un vrai cast à la C++ :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    Pm->register( dynamic_cast<Plugin*>(new BaseRenderer()) );
    (j'ai fait dériver de Plugin plutôt que PluginsManager, ça semble plus logique)
    et dans register downcaster avec dynamic_cast.

    Si j'appelle register avec BaseRenderer, ca passe, alors qu'avec dummyrenderer, ca jette une exception.

    Voilà. Qu'en pensez-vous?

    Merci

    cordialement
    OS : WinXP
    Outils : VC++ 8 (Visual Studio 2005)

  4. #4
    Membre du Club
    Inscrit en
    Juin 2008
    Messages
    85
    Détails du profil
    Informations forums :
    Inscription : Juin 2008
    Messages : 85
    Points : 68
    Points
    68
    Par défaut
    Salut,

    Suite a ton poste j'ai fais des tests. J'ai fais trois classe :
    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
     
    class CTest
    {
    };
     
    class CTest2 : public CTest
    {
    };
     
    cclass CTest3 : public CTest
    {
    public:
    void CTest3::Affiche()
    {
    	cout<<"Bonjour";
    };
    };
     
    void main()
    {
    	CTest2 test2;
    	CTest3* ptr3;
     
    	ptr3 = (CTest3*) &test2;
    	ptr3->Affiche();
    }
    Il me semble qu'une variable ainsi qu'une classe est mis en mémoire uniquement lors de l'instanciation. Ce qui veut dire qu'une variable de type CTest2 est mis en mémoire lors de son instanciation (classe qui ne possède pas la méthode afficher). La ligne CTest3* ptr3; quand a elle ne déclare qu'une case mémoire pour y stocker une adresse (et donc pas une variable de type CTest3). Ce que je ne comprend pas c'est que l'on puisse faire un cast de la classe CTest2 (qui n'a pas de méthode affiche) vers la classe CTest3 et que lorsque l'on fasse afficher() "Bonjour" s'affiche dans la console. La méthode afficher() est mis en mémoire à quel moment? Un pointeur met il du code dans la zone pointée?

  5. #5
    Expert éminent sénior
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2005
    Messages
    5 071
    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 071
    Points : 12 116
    Points
    12 116
    Par défaut
    De toute façon, c'est une très mauvaise idée de partager des classes entre une Dll et un programme car cela entraîne un couplage fort entre ces deux composants logiciels.

  6. #6
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut
    Citation Envoyé par bacelar Voir le message
    De toute façon, c'est une très mauvaise idée de partager des classes entre une Dll et un programme car cela entraîne un couplage fort entre ces deux composants logiciels.
    ++

    Je rajouterais, puisque tu cast 'vers le bas' pourquoi offrir une interface avec PluginsManager? Autant utiliser directement BaseRenderer. Le compilateur te jetteras à ce moment.
    Sinon, un dynamic_cast devrait te retourner un NULL à l'exécution.

  7. #7
    Membre régulier
    Profil pro
    Inscrit en
    Juin 2002
    Messages
    256
    Détails du profil
    Informations personnelles :
    Localisation : Etats-Unis

    Informations forums :
    Inscription : Juin 2002
    Messages : 256
    Points : 121
    Points
    121
    Par défaut
    merci pour vos réponses

    En fait, je me suis rendu compte que ça ne fonctionnait pas correctement avec l'héritage multiple. En gros, si je crée un objet BaseRenderer, que je caste ce dernier en Plugin pour le passer à la DLL, et, enfin, que dans la DLL, l'objet plugin soit downcasté en OpenGLRender (dérivé de BaseRenderer), eh ben soit ca plante, soit (pire!), les fonctions executées sont celles de BaseRenderer (lorsqu'elles sont virtuelles et surchargées dans OpenGLRenderer)!

    Donc je crois que ce n'est effectivement pas la bonne architecture.

    Du coup, je ne sais pas trop comment il faut que je m'y prenne pour faire mon gestionnaire de plugins. L'idée étant, vous l'avez compris, d'avoir une classe abstraite BaseRenderer (quasiment que des méthodes virtuelles pures), et de l'instancier en un type dérivé, uniquement implémenté dans une DLL (OpenGLRenderer n'existera que dans OpenGL.dll, le programme principal ne la connaîtra pas).
    Pour l'instant, je suis plutôt partit pour redéfinir ma fonction Register comme suit :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    class BaseRenderer : public Plugin
    {...}
     
    class OpenGLRenderer : public BaseRenderer 
    {...}
     
    OpenGLRenderer* RegisterPlugin(..) //arguments éventuels
    {
     return (new OpenGLRenderer() );
    }
    et dans mon PluginsManager, pour faire quelque chose du genre (mais là, c'est pas encore fait, et j'ai des doutes sur la façon de faire) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    LoadLibrary(...)
     
    RegisterPl = GetProcAdress(...)
     
    Plugin* Pl = RegisterPl();
    Il semblerait que ça marche, mais j'ai pas encore eu le temps de tester (je ne suis pas chez moi). Par contre, est-ce la technique que vous adopteriez?

    Question subsidiaire : j'ai un attribut de type map<std::string,Plugin*> qui liste les plugins chargés. Si je procède comme j'ai dit, mon Pl a pour "vrai" type "OpenGLRenderer". Lorsque je libère un plugin, je fais faire un truc du genre:

    (dans le programme)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    map<..>::iterator it = ...; //on pointe sur le bon.
     
    delete (*it).second;
     
    m_LoadedPlugins.erase( it );

    Que se passe-t-il? Est-ce que la partie "OpenGLRenderer" (que ne connait pas Plugin) sera bien libérée? Ou bien est-ce qu'il est nécessaire d'appeler une fonction dans la DLL qui libérera l'objet en tant que OpenGLRenderer?

    Bref, est-ce que mon idée est correcte? Si non, comment feriez-vous?

    Merci

    Cordialement
    OS : WinXP
    Outils : VC++ 8 (Visual Studio 2005)

  8. #8
    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 519
    Points
    41 519
    Par défaut
    Ce qui est créé par une DLL doit être détruit par la même DLL.
    Donc, oui, tu dois mettre une fonction de destruction dans ton plugin, ou bien mettre une fonction virtuelle DeleteThis() dans ta classe abstraite.

    Par ailleurs, je te conseille de donner entièrement une sémantique "d'interface" à ta classe: Commencer son nom par I, et déclarer absolument toutes ses fonctions membres comme virtuelles pures.
    Aussi, faire en sorte que tu n'aies jamais besoin de downcaster un pointeur vers ladite interface, sauf dans la DLL qui implémente la classe dérivée.
    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.

  9. #9
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut
    Jettes un coup d'oeil à ce tuto . Il a une section sur un système de plugin. Ca pourra t'inspirer...

  10. #10
    Membre régulier
    Profil pro
    Inscrit en
    Juin 2002
    Messages
    256
    Détails du profil
    Informations personnelles :
    Localisation : Etats-Unis

    Informations forums :
    Inscription : Juin 2002
    Messages : 256
    Points : 121
    Points
    121
    Par défaut
    C'est justement ce tuto qui m'a fait prendre conscience que mon approche initiale n'était pas la bonne. On y a pensé en même temps

    Merci pour vos remarques et votre aide.

    Sinon, si on oublie le côté DLL, je vous repose la question subsidiaire, légèrement modifiée donc. On a les classes suivants :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    class A
    {..}
     
    class B : public A
    {...}
    Puis :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    B* b = new B();
     
    A* a = dynamic_cast<B*>(b);
     
    delete a;
    Le delete supprime-t-il bien "la partie B" cachée dans "a" ou y'aura-t-il une fuite de mémoire?

    Merci

    Cordialement
    OS : WinXP
    Outils : VC++ 8 (Visual Studio 2005)

  11. #11
    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 519
    Points
    41 519
    Par défaut
    1. Il y aura fuite si le destructeur de A n'est pas virtuel
    2. Le delete aura un comportement indéfini s'il n'est pas fait dans le module (Exe, DLL) même qui a fait le new.
    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.

  12. #12
    Membre régulier
    Profil pro
    Inscrit en
    Juin 2002
    Messages
    256
    Détails du profil
    Informations personnelles :
    Localisation : Etats-Unis

    Informations forums :
    Inscription : Juin 2002
    Messages : 256
    Points : 121
    Points
    121
    Par défaut
    Merci !
    OS : WinXP
    Outils : VC++ 8 (Visual Studio 2005)

  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 519
    Points
    41 519
    Par défaut
    Généralement, c'est le genre de classe qui bénéficie d'une fonction membre virtuelle DeleteThis()...
    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 régulier
    Profil pro
    Inscrit en
    Juin 2002
    Messages
    256
    Détails du profil
    Informations personnelles :
    Localisation : Etats-Unis

    Informations forums :
    Inscription : Juin 2002
    Messages : 256
    Points : 121
    Points
    121
    Par défaut
    Peux-tu m'en dire un peu plus à propos de DeleteThis? En effet, sur internet, j'ai trouvé quelques exemples, mais un peu compliqué (typiquement, du code de Valve sur Koders.com, avec un destructeur virtuel protégé, une méthode implémentant un "delete this", etc.).

    On récapitule :
    -dans ma DLL je crée l'objet via RegisterPlugin :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    DLLEXPIMP Plugin* RegisterPlugin()
    {
    	return (new OpenGLRenderer());
    }
    - dans ma DLL je détruis l'objet :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    DLLEXPIMP void UnregisterPlugin(Plugin* Pl)
    {
    	if( Pl )
    		delete (dynamic_cast<OpenGLRenderer*>(Pl));
    }
    -Dans mon programme, je charge le renderer (encore heureux...)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    Pm = new PluginsManager();
     
    				IBaseRenderer* ib = Pm->LoadPlugin<IBaseRenderer>("DXEngine.dll");
    IBaseRenderer étant une inferface définie par :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    class IBaseRenderer : public Plugin
    {
    public:
    	IBaseRenderer() {};
    	IBaseRenderer(const IBaseRenderer& _cpy) : Plugin( _cpy ) 	{};
     
    	virtual ~IBaseRenderer() {};
     
    	virtual void Hello() = 0;
     
    };
    Elle possède donc deux constructeurs (non virtuels donc), et un destructeur virtuel (=>Est ce bien une classe abstraite tel quel?)

    - Dans le programme, lorsque je détruis PluginsManager ou je décharge un plugin, j'appelle UnregisterFc (=pointeur sur UnregisterPlugin) et FreeLibrary

    Donc je ne vois pas trop où je pourrais me servir d'un deleteThis (mais c'est certainement parce que je ne le comprend pas bien!)

    Merci

    Cordialement

    PS : est-ce qu'il y aurait une âme charitable qui, finalement, accepterait de relire/comprendre mon code pour me dire si c'est bien implementé et me faire des suggestions (parce que malgré tout ce que vous m'avez dit, il y a forcément des trucs qui n'iront pas ou que j'aurais mal traduis).
    OS : WinXP
    Outils : VC++ 8 (Visual Studio 2005)

  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 519
    Points
    41 519
    Par défaut
    Déjà, tu ne nommes pas ta fonction RegisterPlugin(). Tu peux la nommer CreatePlugin() si tu veux, mais elle n'enregistre rien. Pareil pour Unregister.

    Pour moi, le plus simple:
    Code C++ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    //Plugin.h
     
    struct IPlugin
    {
    	virtual void DeleteThis(void) = 0;
    	//Autres méthodes
    	virtual UnType Render(Parametres) const = 0;
    };

    Code C++ : 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
    //OpenGLRenderer.cpp
     
    class OpenGLRenderer : public IPlugin
    {
    	virtual void DeleteThis(void);
    	virtual UnType Render(Parametres) const;
    };
     
    void OpenGLRenderer::DeleteThis(void)
    {
    	delete this;
    }
     
    UnType OpenGLRenderer::Render(Parametres) const
    {
    	// ...
    }
     
    EXTERN_C OPENGLRENDERER_API struct IPlugin* __stdcall CreatePlugin(void)
    {
    	return new OpenGLRenderer();
    }
    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
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut
    Citation Envoyé par delire8 Voir le message
    Peux-tu m'en dire un peu plus à propos de DeleteThis?
    Je pense que l'idée c'est quelque chose comme ça:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
     
    class Base
    {
    public:
      void DeleteThis(){delete this;}
    protected:
     virtual ~Base();
    };
    class A :public Base
    {
    protected:
    virtual ~A();
    }
    ....
    Base *p_base(GetBase());
    ....
    // Puis au lieu de faire delete p_base
    p_base->DeleteThis();
    Citation Envoyé par delire8 Voir le message
    - dans ma DLL je détruis l'objet :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    DLLEXPIMP void UnregisterPlugin(Plugin* Pl)
    {
    	if( Pl )
    		delete (dynamic_cast<OpenGLRenderer*>(Pl));
    }
    Comme Monsieur Jourdain, tu fais du delete this sans le savoir....

    Citation Envoyé par delire8 Voir le message
    Elle possède donc deux constructeurs (non virtuels donc), et un destructeur virtuel (=>Est ce bien une classe abstraite tel quel?)
    STOP.
    Un constructeur n'est pas virtuel! En effet, tu spécifies toujours explicitement l'objet que tu construit et la pile des constructeurs est remontée. Donc ça n'a aucun sens.
    Une classe abstraite est une classe que l'on ne souhaite pas qu'elle puisse être instanciée. Pour cela, on y déclare une méthode virtuelle pure (virtual...=0. Cela peut être le destructeur ou toute autre méthode pertinente réalisant l'abstraction.
    Attention à ne pas confondre une classe abstraite avec une classe qui a des membres virtuels. Ce sont deux notions différentes.

    Citation Envoyé par delire8 Voir le message
    - Dans le programme, lorsque je détruis PluginsManager ou je décharge un plugin, j'appelle UnregisterFc (=pointeur sur UnregisterPlugin) et FreeLibrary

    Donc je ne vois pas trop où je pourrais me servir d'un deleteThis (mais c'est certainement parce que je ne le comprend pas bien!)
    Et bien, c'est un peu là que tu t'en sert.

  17. #17
    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 519
    Points
    41 519
    Par défaut
    Ou bien, plus compliqué, si tu veux deux interfaces :
    Code C++ : 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
    //Plugin.h
     
    enum e_pluginType
    {
    	RendererPluginType,
    	OtherPluginType
    };
     
    struct IPlugin
    {
    	virtual void DeleteThis(void) = 0;
    	virtual e_pluginType GetPluginType(void) const = 0;
    };
    struct IRendererPlugin : public IPlugin
    {
    	//Autres méthodes
    	virtual UnType Render(Parametres) const = 0;
    };

    Code C++ : 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
    //OpenGLRenderer.cpp
     
    class OpenGLRenderer : public IRendererPlugin
    {
    	virtual void DeleteThis(void);
    	virtual e_pluginType GetPluginType(void) const ;
    	virtual UnType Render(Parametres) const;
    };
     
    void OpenGLRenderer::DeleteThis(void)
    {
    	delete this;
    }
     
    e_pluginType OpenGLRenderer::GetPluginType(void) const
    {
    	return RendererPluginType;
    }
     
    UnType OpenGLRenderer::Render(Parametres) const
    {
    	// ...
    }
     
    EXTERN_C OPENGLRENDERER_API struct IPlugin* __stdcall CreatePlugin(void)
    {
    	return new OpenGLRenderer();
    }
    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.

  18. #18
    Membre régulier
    Profil pro
    Inscrit en
    Juin 2002
    Messages
    256
    Détails du profil
    Informations personnelles :
    Localisation : Etats-Unis

    Informations forums :
    Inscription : Juin 2002
    Messages : 256
    Points : 121
    Points
    121
    Par défaut
    Concernant le nom des fonctions, tu as parfaitement raison.

    Merci pour l'exemple d'implémentation.
    OS : WinXP
    Outils : VC++ 8 (Visual Studio 2005)

  19. #19
    Membre régulier
    Profil pro
    Inscrit en
    Juin 2002
    Messages
    256
    Détails du profil
    Informations personnelles :
    Localisation : Etats-Unis

    Informations forums :
    Inscription : Juin 2002
    Messages : 256
    Points : 121
    Points
    121
    Par défaut
    Mes excuses, nous nous sommes croisés.

    Merci pour vos explications et exemples très clairs! Si j'ai bien compris, avec le DeleteThis, plus besoin d'avoir une fonction DestroyPlugin (=UnregisterPlugin actuellement) dans ma DLL?

    Par contre, l'un propose un DeleteThis virtuel pur mais pas l'autre. Quelle différence? J'opterais plutôt pour le DeleteThis non virtuel, histoire de ne pas avoir à le coder dans toutes les classes dérivées. Sauf que dans mon cas, j'ai Plugin, IBaseRenderer:lugin (Interface donc), OpenGLRenderer::IBaseRenderer => est-ce que je ne risque pas de "casser" le côté Interface de IBaseRenderer en la faisant dériver d'une classe "en dur" ?

    Merci encore pour votre patience !

    Cordialement
    OS : WinXP
    Outils : VC++ 8 (Visual Studio 2005)

  20. #20
    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 519
    Points
    41 519
    Par défaut
    Citation Envoyé par delire8 Voir le message
    est-ce que je ne risque pas de "casser" le côté Interface de IBaseRenderer en la faisant dériver d'une classe "en dur" ?
    C'est comme ça que je le vois, en tout cas. D'où nécessité du DeleteThis() virtuel.
    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.

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

Discussions similaires

  1. [POO] Héritage et méthode non implémentée
    Par Keweed dans le forum C++
    Réponses: 10
    Dernier message: 08/12/2008, 15h14
  2. Réponses: 2
    Dernier message: 29/03/2007, 12h02
  3. [POO] Pointeur sur fonction membre et héritage
    Par MrDuChnok dans le forum C++
    Réponses: 9
    Dernier message: 20/07/2006, 17h19
  4. Réponses: 8
    Dernier message: 29/06/2006, 14h54
  5. Le linker ignore les fonctions non implémentées
    Par Rodrigue dans le forum C++Builder
    Réponses: 5
    Dernier message: 02/03/2005, 13h31

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