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 :

Problème : conflit Pure Interface et Singleton


Sujet :

C++

  1. #1
    Membre habitué
    Inscrit en
    Octobre 2005
    Messages
    141
    Détails du profil
    Informations personnelles :
    Âge : 32

    Informations forums :
    Inscription : Octobre 2005
    Messages : 141
    Points : 135
    Points
    135
    Par défaut Problème : conflit Pure Interface et Singleton
    Bonjour !

    J'essaye de faire une bibliothèque (une DLL plus précisément). Pour cela, j'utilise la technique Pure Interface pour cacher l'implementation de mon moteur, sauf que mon moteur (qui dérive de l'interface) est un singleton (constructeur/destructeur caché).

    Le problème étant que mon interface nommé ISDLGRAPHICS a besoin du constructeur de SDLGRAPHICS pour le construire. Donc un conflit apparait et l'interface ne pourra jamais creer une instance de SDLGRAPHICS...

    Si je mets le constructeur de SDLGRAPHICS en public, je perds un avantage du singleton.

    Et si je mets le singleton dans mon interface, aucune utilité, je ne pourrais pas faire d'instance car mon interface ne connait pas sa classe dérivée (logique).

    Voici les 4 fichiers (seulement les fichiers concernés, les autres sont des classes ou des défines en dehors du problème) :

    ISDLGRAPHICS.h
    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
    #pragma once
     
    #include <iostream>
    #include <sstream> 
     
    #include <SDL/SDL.h>
    #include <SDL/SDL_TTF.h>
    #include <SDL/SDL_Image.h>
     
    #ifdef __DEBUG__
    #include <windows.h>
    #endif
     
    #include "COLOR3.h"
     
    class ISDLGRAPHICS
    {
    public:
    	static ISDLGRAPHICS *Create();
     
    	virtual void FlipScreen() = 0;
     
    	virtual void ClearScreen(COLOR3 clearcolor = COLOR3(255,255,255)) = 0;
     
    	virtual void BuildWindow(std::string caption, int width, int height, int bpp) = 0;
     
    	virtual void ApplySurface(int x, int y, SDL_Surface* source, 
    		SDL_Surface* destination = NULL, SDL_Rect* clip = NULL) = 0;
     
    	virtual void ApplySurface(SDL_Rect *pos, SDL_Surface* source, 
    		SDL_Surface* destination = NULL, SDL_Rect* clip = NULL) = 0;
     
    	virtual SDL_Surface* LoadSurface(std::string filename) = 0;
     
    	virtual SDL_Surface* CreateShape(int width, int height, COLOR3 color) = 0;
     
    	virtual std::string MakeWindowCaption() = 0;
    };
    ISDLGRAPHICS.cpp
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    #include "SDLGRAPHICS.h"
     
    ISDLGRAPHICS *ISDLGRAPHICS::Create()
    {
    	//Voici ce que je devrais faire:
    	//return new SDLGRAPHICS;
    }
    SDLGRAPHICS.h
    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
    #pragma once
     
    #include "ISDLGRAPHICS.h"
     
    class SDLGRAPHICS : public ISDLGRAPHICS
    {
    private:
    //-------------------------------------------------------------------------
    //--Singleton--------------------------------------------------------------
    //-------------------------------------------------------------------------
    	SDLGRAPHICS() { }
    	~SDLGRAPHICS() { }
     
    	static SDLGRAPHICS *Moteur;
    //-------------------------------------------------------------------------
     
    	SDL_Surface* m_Screen;
     
    public:
    //-------------------------------------------------------------------------
    //--Singleton--------------------------------------------------------------
    //-------------------------------------------------------------------------
    	static SDLGRAPHICS *GetInstance()
    	{
    		if (Moteur == NULL)
    		{
    			Moteur = new SDLGRAPHICS;
    		}
     
    		else
    		{
    			return NULL;
    		}
     
    		return Moteur;
    	}
     
    	static void KillInstance()
    	{
    		if (Moteur != NULL)
    		{
    			delete Moteur;
    			Moteur = NULL;
    		}
     
    		SDL_Quit();
    	}
    //-------------------------------------------------------------------------
     
    	void FlipScreen();
     
    	void ClearScreen(COLOR3 clearcolor = COLOR3(255,255,255));
     
    	void BuildWindow(std::string caption, int width, int height, int bpp);
     
    	void ApplySurface(int x, int y, SDL_Surface* source, SDL_Surface* destination = NULL,
    		SDL_Rect* clip = NULL);
     
    	void ApplySurface(SDL_Rect *pos, SDL_Surface* source, SDL_Surface* destination = NULL,
    		SDL_Rect* clip = NULL);
     
    	SDL_Surface* LoadSurface(std::string filename);
     
    	SDL_Surface* CreateShape(int width, int height, COLOR3 color);
     
    	std::string MakeWindowCaption();
    };
     
    SDLGRAPHICS* SDLGRAPHICS::Moteur = NULL;
    SDLGRAPHICS.cpp
    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
    #include "SDLGRAPHICS.h"
     
    SDL_Surface* SDLGRAPHICS::LoadSurface(std::string filename)
    {
    	SDL_Surface *image = NULL;
     
    	image = IMG_Load(filename.c_str());
     
    	if (image != NULL)
    	{
    		// On utilise le mangenta comme couleur a enlever (r:255;g:0;b:255)
    		Uint32 colorkey = SDL_MapRGB(image->format, 0, 255, 255);
     
    		SDL_SetColorKey(image, SDL_RLEACCEL | SDL_SRCCOLORKEY, 
    			colorkey);
    	}
     
    #ifdef __DEBUG__
    	else
    	{
    		std::stringstream ss;
     
    		ss << "Erreur lors du chargement de l'image '" << filename << endl;
     
    		OutputDebugString(ss.str().c_str());
    	}
    #endif
     
    	return image;
    }
     
    void SDLGRAPHICS::ApplySurface(int x, int y, SDL_Surface* source, SDL_Surface* destination,
    				   SDL_Rect* clip)
    {
    	SDL_Rect offset; 
     
    	offset.x = x;
    	offset.y = y; 
     
    	if (destination == NULL)
    	{
    		SDL_BlitSurface(source, clip, m_Screen, &offset);
    	}
     
    	else
    	{
    		SDL_BlitSurface(source, clip, destination, &offset);
    	}
    }
     
    void SDLGRAPHICS::BuildWindow(std::string caption, int width, int height, int bpp)
    {
    	SDL_Init(SDL_INIT_VIDEO);
     
    	SDL_ShowCursor(SDL_DISABLE);
     
    	m_Screen = SDL_SetVideoMode(width, height, bpp, SDL_HWSURFACE | SDL_DOUBLEBUF);
     
    	SDL_WM_SetCaption(caption.c_str(), NULL);
    }
     
    std::string SDLGRAPHICS::MakeWindowCaption()
    {
    	std::stringstream ss;
     
    	ss << SCREEN_CAPTION << BUILD;
     
    	std::string ret = ss.str();
     
    	return ret;
    }
     
    SDL_Surface* SDLGRAPHICS::CreateShape(int width, int height, COLOR3 color)
    {
    	SDL_Surface *shape;
     
    	shape = SDL_CreateRGBSurface(SDL_HWSURFACE, width, height, SCREEN_BPP, 0, 0, 0, 0);
     
    #ifdef __DEBUG__
    	if (shape == NULL)
    	{
    		OutputDebugString("Erreur lors de la création du rectangle!");
    	}
    #endif
     
    	SDL_FillRect(shape, NULL, SDL_MapRGB(m_Screen->format, color.r, color.g, color.b));
     
    	return shape;
    }
     
    void SDLGRAPHICS::ApplySurface(SDL_Rect *pos, SDL_Surface* source, 
    							   SDL_Surface* destination,	SDL_Rect* clip)
    {
    	if (destination == NULL)
    	{
    		SDL_BlitSurface(source, clip, m_Screen, pos);
    	}
     
    	else
    	{
    		SDL_BlitSurface(source, clip, destination, pos);
    	}
     
    }	
     
    void SDLGRAPHICS::FlipScreen()
    {
    	SDL_Flip(m_Screen);
    }
     
    void SDLGRAPHICS::ClearScreen(COLOR3 clearcolor)
    {
    	SDL_FillRect(m_Screen, NULL, SDL_MapRGB(m_Screen->format, 255, 255, 255));
    }
    Merci pour votre aide.

  2. #2
    Expert éminent

    Homme Profil pro
    Ingénieur systèmes et réseaux
    Inscrit en
    Février 2007
    Messages
    4 253
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur systèmes et réseaux
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Février 2007
    Messages : 4 253
    Points : 7 618
    Points
    7 618
    Billets dans le blog
    3
    Par défaut
    Je suis pas sur de bien comprendre... L'utilité d'avoir une interface est de pouvoir interchanger les implémentations de maniere transparente (voire d'en avoir plusieurs instanciées en même temps).

    Si c'est une fonction statique de l'interface qui crée l'instance, alors l'implémentation est fixe, et il n'y a pas d'interet à utiliser une interface.
    Imaginons une seconde DLL avec une seconde implémentation... Quelle static ISDLGRAPHICS *Create(); sera utilisée ?


    Il y a plusieurs solutions à ce problême:
    Dans tous les cas, il faut sortir la fonction static ISDLGRAPHICS *Create();
    D'ailleurs, pour qu'elle soit accessible de l'exterieur de la DLL, il faut l'exporter...

    Méthode bourrine:
    - Faire une fonction extern "C" ISDLGRAPHICS * Create();. Ca sera la seule fonction exportée de la DLL.
    - Au chargement de la DLL par LoadLibrary, il suffit de faire un GetProcAddress ou un truc du genre, et c'est gagné.


    Méthode COM:
    - Transformer ISDLGRAPHICS en une vraie interface COM (y a pas beaucoup de boulot: IID, AddRef/Release/QueryInterface).
    - Rajouter les fonctions ad-hoc dans la DLL:
    - CoRegisterServer / CoUnregisterServer
    - CoCreateFactory (ou un truc du genre, voir la doc).
    - Exporter un CLSID pour cette implémentation.

    Dans le programme source:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    CoInitialize();
    ISDLGRAPHICS* pSDLGraphics;
    HRESULT hres = CoCreateInstance(CLSID, IID, (void**)&pSDLGraphics);
    if (SUCCEEDED(hres)) {
       ... pSDLGraphics usage ...
       pSDLGraphics->Release();
    }
    CoUninitialize();
    Cette derniere méthode a l'avantage de permettre le déploiement de nouvelles implémentations simplement par enregistrement de la DLL dans le système.

  3. #3
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 382
    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 382
    Points : 41 590
    Points
    41 590
    Par défaut
    +1 pour nicroman, tu dois sortir la création/instanciation de l'interface.
    Une interface n'est pas censée pouvoir créer à partir de rien: Elle ne peut qu'ordonner à un objet d'en créer un autre (par clonage ou par pattern "factory").

  4. #4
    Membre habitué
    Inscrit en
    Octobre 2005
    Messages
    141
    Détails du profil
    Informations personnelles :
    Âge : 32

    Informations forums :
    Inscription : Octobre 2005
    Messages : 141
    Points : 135
    Points
    135
    Par défaut
    Merci pour vos deux réponses.

    Si c'est une fonction statique de l'interface qui crée l'instance, alors l'implémentation est fixe, et il n'y a pas d'interet à utiliser une interface.
    Imaginons une seconde DLL avec une seconde implémentation... Quelle static ISDLGRAPHICS *Create(); sera utilisée ?
    Bah si je veux faire quelque chose avec OpenGL, je vais pas faire une nouvelle DLL, je vais rajouter des fichiers dans celle-ci, et dans ma static Create, je rajoute un switch (avec une énum):

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    IGRAPHICS *IGRAPHICS::Create(int type)
    {
         switch(type)
         {
         case eFACTORYTYPE_SDL:
              return new SDLGRAPHICS;
              break;
     
         case eFACTORYTYPE_OPENGL:
              return new OPENGLGRAPHICS;
              break;
         }
    }
    (Indentation à la main, c'est juste pour l'idée).

    Je vais me renseigner pour transformer mon interface en COM. La programmation Windows et moi pour le moment, c'est pas l'extase.

  5. #5
    Expert éminent

    Homme Profil pro
    Ingénieur systèmes et réseaux
    Inscrit en
    Février 2007
    Messages
    4 253
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur systèmes et réseaux
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Février 2007
    Messages : 4 253
    Points : 7 618
    Points
    7 618
    Billets dans le blog
    3
    Par défaut
    Mais justement....

    Ton exemple prouve bien que ta fonction connait toutes les implémentations possibles... et n'a donc rien à voir avec l'interface...

    Il faut sortir la fonction de l'interface.
    1. L'interface n'est pas exportée par la DLL.
    2. La fonction "factory" est exportée par la DLL.

    Je continue de penser qu'une factory exportée par une DLL qui connaitrait toutes les instanciations possibles c'est cher payer (en temps de conception) pour pas grand chose... La DLL se comporterait comme plug-in je dis pas, mais dans ce cas, point de factory ominsciente possible.

    Quant à COM, sur le principe de base, ca n'a rien a voir avec Windows.
    Le CoCreateInstance et la notion de server par contre oui.

Discussions similaires

  1. énorme problème avec mon interface MFC
    Par cenedra dans le forum MFC
    Réponses: 23
    Dernier message: 17/07/2006, 10h36
  2. Problème avec deux interfaces
    Par ikeaboy dans le forum Langage
    Réponses: 2
    Dernier message: 28/05/2006, 15h56
  3. Pb de pure interface
    Par drcd dans le forum C++
    Réponses: 12
    Dernier message: 05/03/2006, 12h11
  4. [EJB] Problème avec l'interface locale d'un bean
    Par clement42 dans le forum Java EE
    Réponses: 2
    Dernier message: 07/01/2006, 10h24
  5. Réponses: 1
    Dernier message: 08/03/2005, 16h19

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