[C++] Premier constructeur & dernier destructeur spécifiques....

Premier constructeur & dernier destructeur spécifiques.... [C++] - C++ - Programmation

Marsh Posté le 01-02-2004 à 19:15:39    

Besoin :
 
Certaines classes nécessitent une initialisation ou une désinitialisation particulières qui ne doivent intervenir qu'UNE seule fois dans la vie d'un programme. Cela indépendament du nombre de fois que la classe est instanciée!  [:airforceone]  
 
Objectif :
 
Définir une classe de base qui se caractérise par l'appel d'un constructeur et d'un destructeur spécifiques respectivement au premier appel et au dernier appel lors de l'execution d'un programme.  
 
Exemple :
 
Concrètement, prennons par exemple une classe qui encapsule la gestion d'un Socket sous windows. Il est nécéssaire dans le constructeur d'effectuer une initialisation de la librairie WinSock2. Et dans le destructeur, il est nécessaire de relacher cette même librairie.
 
Cette classe pourrait donc ressembler à ceci :

Code :
  1. class CSocket // rien à voir avec MFC !
  2. {
  3. public:
  4.   CSocket() {
  5.     WSADATA wsaData;
  6.     WSAStartup(MAKEWORD(2,2),&wsaData); }
  7.   ~CSocket() {
  8.     WSACleanup(); }
  9. }


 
Le problème de cette classe et qu'à chaque intanciation, le constructeur (et ensuite le destructeur) sont appellés systématiquement multipliant l'initialisation et la libération de la librairie WinSock. Dans ce cas précis, cela ne pose aucun problème (la librairie WinSock s'en accomode parfaitement).
 
Proposition :
 
Créer une classe de base qui execute les fonctions membres "PremierConstructeur" et "Dernier Constructeur" respectivement lors du premier appel du constructeur et lors du dernier appel du destructeur. Faire hériter de cette classe de base toutes les classes tel que CSocket.
 
Cette classe de base pourrait ressembler à ceci :

Code :
  1. class Cinit
  2. {
  3. public:
  4.   Cinit() {
  5.     if( cpt++ == 0 )
  6.        PremierConstructeur(); }
  7.   ~Cinit() {
  8.     if( --cpt == 0 )
  9.        DernierDestructeur(); }
  10.   virtual void PremierConstructeur() = 0;
  11.   virtual void DernierDestructeur() = 0;
  12. private:
  13.   static int cpt;
  14. }


 
Ne pas oublier dans le code d'ajouter :
 

Code :
  1. int Cinit::cpt = 0;


 
Retour à l'exemple :
 
Revenons à notre classe CSocket :

Code :
  1. class CSocket : public Cinit
  2. {
  3. public:
  4.   CSocket();
  5.   ~CSocket();
  6. private:
  7.   void PremierConstructeur() {
  8.     WSADATA wsaData;
  9.     WSAStartup(MAKEWORD(2,2),&wsaData); }
  10.   void DernierDestructeur() {
  11.     WSACleanup(); }
  12. }


 
La suite... :
 
Maintenant, ce mécanisme est loin d'être parfait et en fait tres peu exploitable. Au mieux, c'est le point de départ (en espérant etre parti dans la bonne direction).  :??:  
 
Les problèmes sont les suivants :
 
1) Cette classe ne gère l'initialisation que d'une seule classe dériviée. On ne peut pas s'en servir pour initiliser plusieurs classes dériviées différentes. Il faut mêtre en cause le compteur qui est unique et propre à la classe Cinit alors qu'il faudrait l'intégrer dans la classe dérivée. Problème, je voudrais éviter au maximum d'altérer les classes dériver et rendre ce mécanisme transparent !
 
2) Le premier constructeur et le dernier destructeur ne peuvent être exploités que par la classe dérivée. Les classes dérivées des dérivées n'en profitent pas. Cela n'est pas un réel problème, il suffit de faire hériter de Cinit l'ensemble des classes, mais dans ce cas on retombe dans le problème n°1.
 
J'entrevois peut etre une solution qui consisterait à détecter quelle classe appelle les fonctions membres virtuelles PremierC et DernierD et de gérer automatiquement un compteur static par type de classe (une list:: qui compte/décompte séparement pour chaque classe dérivant de Cinit).
 
Quelqu'un à une meilleure idée d'implémentation. Aujourd'hui, j'ai plusieurs classes vraiment différentes qui doivent implémenter ce type d'initilisation/désinitialisation et j'implémente le mécanisme dans chaque classe. Ca fait du code à dupliquer....pour rien.
 
Merci d'avance.  :hello:  
   Xter.


Message édité par xterminhate le 01-02-2004 à 20:26:38
Reply

Marsh Posté le 01-02-2004 à 19:15:39   

Reply

Marsh Posté le 01-02-2004 à 22:28:58    

genre ça s'appelle un singleton. ta solution elle est bancale et très très laide

Reply

Marsh Posté le 01-02-2004 à 22:37:52    

if( --cpt == 0 ) >> c pas plutot if( cpt-- == 0 ) ?


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

Marsh Posté le 01-02-2004 à 22:57:53    

c'est mauvais de toutes façons

Reply

Marsh Posté le 01-02-2004 à 23:04:17    

Tu es sur BlackGoddess ? Prennons un cas simple :
 
valeur initiale : cpt = 0
premier construct -> (cpt++==0) est vrai
valeur : cpt = 1
dernier destructeur -> (--cpt==0) est vrai
valeur : cpt = 0
 
Taz : j'ignorais ce qu'etait un singleton ! Je vais m'instruire, ca semble correspondre à peu pres à ce que je cherche... enfin plus ou moins.
 
Merci,
   Xter.


Message édité par xterminhate le 01-02-2004 à 23:09:17
Reply

Marsh Posté le 01-02-2004 à 23:08:56    

en tout cas c'est pas malin de pas avoir penser à une instance statique DonnéePrivée

Reply

Marsh Posté le 01-02-2004 à 23:10:39    

sincèrement je pensais qu'il etait possible de déclarer static une classe :
 

Code :
  1. class Ctoto : static Cinit
  2. {
  3. /* .... */
  4. }


 
 
 
 

Reply

Marsh Posté le 01-02-2004 à 23:15:16    

euh moi aussi

Reply

Marsh Posté le 02-02-2004 à 09:31:25    

xterminhate a écrit :

sincèrement je pensais qu'il etait possible de déclarer static une classe :
 

Code :
  1. class Ctoto : static Cinit
  2. {
  3. /* .... */
  4. }


 


 
ca compile pas ca chez moi !?
 
par contre cela oui :
 

Code :
  1. #include <iostream>
  2. struct init
  3. {
  4. init()
  5. {
  6.  std::cout << "init.ctor\n";
  7. }
  8. ~init()
  9. {
  10.  std::cout << "init.dtor\n";
  11. }
  12. };
  13. class test
  14. {
  15. static init i;
  16. public:
  17. test()
  18. {
  19.  std::cout << "test.ctor\n";
  20. }
  21. ~test()
  22. {
  23.  std::cout << "test.dtor\n";
  24. }
  25. };
  26. init test::i;
  27. int main
  28. {
  29. test();
  30. }


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

Marsh Posté le 02-02-2004 à 12:23:46    

voilà

Reply

Marsh Posté le 02-02-2004 à 12:23:46   

Reply

Marsh Posté le 02-02-2004 à 19:17:40    

Blackgoddess : Effectivement, c'est la solution la plus séduisante. Cela force à créer explicitement une classe de base servant à l'initialisation dont le constructeur et le desctructeur s'executent en début et fin de programme. Parfait.
 
Je vais tout de même creuser un peu le "singleton pattern" histoire de pas mourir idiot.
 
Merci à vous deux :p
   Xter.

Reply

Marsh Posté le 02-02-2004 à 19:22:45    

je serais content si tu pouvais mettre un résumé de ce que tu auras appris la dessus :) (ou des liens utiles)
merci :)


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

Sujets relatifs:

Leave a Replay

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