[C++] Urgent SVP!! Fabrique abstraite : probleme de cast

Urgent SVP!! Fabrique abstraite : probleme de cast [C++] - C++ - Programmation

Marsh Posté le 23-12-2005 à 15:30:14    

Hello,
 
J'ai fait une fabrique d'objet
 
class SimpleClassFactory
   {
   public:
      SimpleBaseClass *createInstance1() {return new SimpleClass1;}
      SimpleBaseClass *createInstance2() {return new SimpleClass2;}
   };

 
basee sur la modele de classe ci-dessous:
 
class SimpleBaseClass
   {
   public:
      virtual int  getValue()          = 0;
      virtual void setValue(int value) = 0;
   };
 
class SimpleClass1 : public SimpleBaseClass
   {
   public:
      int  getValue()          {return m_value;}
      void setValue(int value) {m_value = value;}
      int getToto1() {return toto1};
   private:
      int m_value;
      int toto1;
   };
 
class SimpleClass2 : public SimpleBaseClass
   {
   public:
      int  getValue()          {return m_value*100;}
      void setValue(int value) {m_value = value;}
      int getToto2() {return toto2};
   private:
      int m_value;
      int toto2;
   };

 
En gros, je veux pouvoir utiliser ma fabrique comme distributeur d'objet, mais des objets qui peuvent avoir des comportement supplementaires differents de ma classe de base : comme getToto1() et getToto2() par exemple.
 
Lorsque je teste, j'ecris :
SimpleClassFactory factory;
SimpleBaseClass * monObjet = factory.createInstance1() //par exemple;
int a = monObjet->getValue();

 
Jusque la tout va bien! Mais lorsque j'essaie:
int b = monObjet->getToto1()
 
Je recois une erreur de compil me disant que la methode getToto1() n'est pas membre de l'objet SimpleBaseClass, ce que je peux comprendre vu que ma fabrique renvoit effectivement un objet SimpleBaseClass. Avec un cast ca ne marche pas mieux:
 
SimpleBaseClass * monObjet = (SimpleClass1 *)factory.createInstance1()
 
D'ou ma question: suis-je obligee d'instancier un objet de type SimpleClass1 pour acceder aux methodes de celui-ci via instanciation avec la fabrique:
SimpleClass1 * monObjet = factory.createInstance1()
car comme cela ca marche...
 
Ou y'a-t-il un moyen d'utiliser un objet SimpleBaseClass? Mon but etant vous l'aurez compris d'utiliser toujours le meme objet (SimpleBaseClass) pour acceder a n'importe quelle instanciation de la classe SimpleBaseClass. (pour des raisons de reduction de modification du code si jamais il venait a devoir utiliser une autre instanciation)
 
Merci d'avance.

Reply

Marsh Posté le 23-12-2005 à 15:30:14   

Reply

Marsh Posté le 23-12-2005 à 15:33:05    

balises cpp ...

Reply

Marsh Posté le 23-12-2005 à 15:34:37    

Pourrais-tu etre plus explicite stp? Un exemple peut-etre ou un lien?

Reply

Marsh Posté le 23-12-2005 à 15:34:38    

on ne fait pas de casts C !
 
si tu es certain que ton objet est de la classe SimpleClass1, alors tu fais comme suit :
 

Code :
  1. SimpleClass1 *monInstance = static_cast<SimpleClass1>factory.createInstance1();


 
Edit : au passage : où est l'utilité de faire une factory si tu dois utiliser des méthodes différentes pour accéder aux instances des classes différentes ? c'est complètement inutile, là, hein ....


Message édité par theshockwave le 23-12-2005 à 15:35:39
Reply

Marsh Posté le 23-12-2005 à 15:36:12    

agyspace a écrit :

Pourrais-tu etre plus explicite stp? Un exemple peut-etre ou un lien?


pour les balises CPP, je parlais de la mise en forme de ton message qui est affreusement illisible :)

Reply

Marsh Posté le 23-12-2005 à 15:51:41    

En bref tu me dis d'utiliser nun cast C++ plutot qu'un cast C. Soit!
 
J'ai donc 2 questions:
 
1. quelle est la difference fondamentale entre faire un cast style C et faure un static_cast? Question de performance ou question de philosophie?
 
2. en ecrivant ce que tu proposes ca marche effectivement (j'ai remplace le cast C par un cast C++ bien que le cast C marchait bien). C'est donc le seul moyen pour pouvoir acceder a la methode getToto1()? Il n'y a pas une ruse quelconque pour utiliser SimpleBaseClass?
 
Merci de ta reponse en tous cas.

Reply

Marsh Posté le 23-12-2005 à 15:53:13    

theshockwave a écrit :

pour les balises CPP, je parlais de la mise en forme de ton message qui est affreusement illisible :)


 
Ah oui c'est vrai qu'il etait un peu long...Dsl   :sweat: C'est quoi les balises CPP? Ca permet de mettre en forme les messages que tu postes?

Reply

Marsh Posté le 23-12-2005 à 15:57:48    

Citation :

SimpleBaseClass * monObjet = (SimpleClass1 *)factory.createInstance1()


 
Whah
 
tu convertis le resultat de createInstance1 (=SimpleBaseClass *) en SimpleClass1 *, que tu stockes dans un....;SimpleBaseClass  * !
 

Reply

Marsh Posté le 23-12-2005 à 16:00:39    

agyspace a écrit :

En bref tu me dis d'utiliser nun cast C++ plutot qu'un cast C. Soit!
 
J'ai donc 2 questions:
 
1. quelle est la difference fondamentale entre faire un cast style C et faure un static_cast? Question de performance ou question de philosophie?
 
2. en ecrivant ce que tu proposes ca marche effectivement (j'ai remplace le cast C par un cast C++ bien que le cast C marchait bien). C'est donc le seul moyen pour pouvoir acceder a la methode getToto1()? Il n'y a pas une ruse quelconque pour utiliser SimpleBaseClass?
 
Merci de ta reponse en tous cas.


un cast C++ décrit aussi ce que tu sous-entend derrière ce cast (d'où la présence des dynamic_cast, reinterpret_cast, const_cast, etc ...) et tu peux avoir des mises en garde si ce que tu fais n'est pas logique du point de vue de ton compilateur. Ensuite, pour le dynamic_cast, par exemple, ce n'est pas qu'un simple cast C, loin de là, je t'invite à lire de la doc à ce sujet quand tu en auras le temps
 
tu manipules des pointeurs sur une interface donnée. Tu ne peux donc évidemment accéder qu'aux méthodes de cette interface ... Si tu veux des méthodes spécifiques à une classe qui implémente cette interface, alors il faut récupérer un pointeur sur l'interface qu'il te faut via un cast (static_cast parce que tu sais ce que va te renvoyer ta méthode à l'avance, c'est d'ailleurs pour cela que je conteste son utilité). il n'y a pas d'autre méthode ...
 

Reply

Marsh Posté le 23-12-2005 à 16:01:40    

et le destructeur virtuel !
 
pas de static_cast ni rien. Tu changes la signature de tes fonctions membres et voilou

Reply

Marsh Posté le 23-12-2005 à 16:01:40   

Reply

Marsh Posté le 23-12-2005 à 16:01:42    

agyspace a écrit :

Ah oui c'est vrai qu'il etait un peu long...Dsl   :sweat: C'est quoi les balises CPP? Ca permet de mettre en forme les messages que tu postes?


ce n'est pas une question de longueur. ces balises sont prévues pour mettre en forme le code d'une manière plus adaptée (coloration syntaxique, numérotation des lignes)

Reply

Marsh Posté le 23-12-2005 à 16:02:59    

Taz a écrit :

et le destructeur virtuel !
 
pas de static_cast ni rien. Tu changes la signature de tes fonctions membres et voilou


 
ah tiens, ouais, le destructeur virtuel n'est pas là [:petrus75]
 
et pour les fonctions membres, justement, à quoi cela sert-il de les avoir si on crée toujours des instances de la même classe ?  :heink:

Reply

Marsh Posté le 23-12-2005 à 16:30:29    

theshockwave a écrit :

ah tiens, ouais, le destructeur virtuel n'est pas là [:petrus75]
 
et pour les fonctions membres, justement, à quoi cela sert-il de les avoir si on crée toujours des instances de la même classe ?  :heink:


 
1. Heu pour le constructeur virtuel, il va me servir a quoi au juste?
 
2. En gros la classe de base contient les methodes communes a toutes les instances possible.
Chaque instance correspond a une version definie de l'api que j'ecris. En clair, si je dois modifier l'implementation d'une methode commune ou si je dois rajouter une nouvelle fonctionnalite, je le ferai dans une nouvelle classe d'instance de la classe SimpleBaseClass. Et je dirai aux gens qui utilisent mon Api, maintenant vous passez a telle implementation pour avoir les nouvelles fonctionnalites de l'Api. C'est pour ca que le fait de devoir demander aux clients de modifier leur code (pour changer le type d'objet a recuperer) me derangeait mais j'ai trouve un astuce (via utilisation de typedef).

Reply

Marsh Posté le 23-12-2005 à 16:36:20    

agyspace a écrit :


1. Heu pour le constructeur virtuel, il va me servir a quoi au juste?


 
destructeur ...

Reply

Marsh Posté le 23-12-2005 à 17:03:17    

Oui mais un destructeur n'est-il pas utile que s'il y a quelque chose a detruire?
 
Dans les classes filles, il n'y a aucun pointeur en attribut, je vais pas faire un delete sur des entiers ou des strings? Non?
 
Si j'utilise le destructeur par defaut dans mes classes filles (cad que je ne declare pas de destructeur) faut-il quand meme que je declare un constructeur virtuel dans ma classe abstraite?

Reply

Marsh Posté le 23-12-2005 à 17:09:22    

oui, un destructeur virtuel trivial
 
virtual ~nomclasse() {}


---------------
-( BlackGoddess )-
Reply

Marsh Posté le 23-12-2005 à 17:43:55    

Je fais cours alors ça a peut être été dit.
 
getToto1() appartient à la classe SimpleClass1
getToto2() appartient à la classe SimpleClass2
Ni l'une ni l'autre n'appartient à la classe SimpleBaseClass
 
Donc le code suivant

Code :
  1. SimpleClassFactory factory;
  2. SimpleBaseClass * monObjet = factory.createInstance1() //par exemple;
  3. int a = monObjet->getToto1();


Echoue à la compilation en ligne 3 car monObjet est du type SimpleBaseClass* et non pas SimpleClass1*.
 
Solutions:
 
Au choix :  
- changer le type de retour de SimpleClassFactory::createInstance1()
et SimpleClassFactory::createInstance2() respectivement en SimpleClass1* et SimpleClass2*.
- Faire un cast static_cast<SimpleClassN*> du pointeur retourné et l'associer à un pointeur SimpleClassN*. N correspondant à 1 ou 2 (je ne vais pas faire un dessin)
 
Perso je préfèrerai la première solution moins dangereuse.


Message édité par slash33 le 23-12-2005 à 17:48:59
Reply

Marsh Posté le 23-12-2005 à 19:05:28    

bin suivant la 1ere solution il n'y a plus de fabrique
 
je n'arrive toujours pas à saisir pourquoi tu veux faire une classe de base commune (ce qu'on appelerait même interface dans d'autres langages), utiliser un pattern factory, qui sert justement à abstraire le type réel, pour ensuite t'amuser à revenir vers ce type réel pour faire des opérations spécifiques.
 
edit : si tu choisis la 2eme solution, n'oublie pas de vérifier si static_cast<SimpleClassN*>(tonobjet) retourne NULL ou pas -> si le cast a échoué ou réussi.


Message édité par blackgoddess le 23-12-2005 à 19:07:23

---------------
-( BlackGoddess )-
Reply

Marsh Posté le 28-12-2005 à 09:50:01    

Ok merci pour toutes vos reponses :)

Reply

Marsh Posté le 28-12-2005 à 09:54:03    

tu m'appelles si tu vois un static_cast<T*>(obj) == 0 avec obj != 0

Reply

Marsh Posté le 28-12-2005 à 10:00:40    

mmh oui, en effet je me suis trompé :p  
je voulais parler de dynamic_cast<SimpleClassN*>(tonobjet)


---------------
-( BlackGoddess )-
Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed