Foros del Web » Programación para mayores de 30 ;) » C/C++ »

¿Porque el constructor afuera de la clase?Singleton

Estas en el tema de ¿Porque el constructor afuera de la clase?Singleton en el foro de C/C++ en Foros del Web. Bueno estoy desarrollando el patron singleton en C++ utilizando Dev C++, y lo tengo ya listo, pero quiero aclarar conceptos. yo tenia el constructor dentro ...
  #1 (permalink)  
Antiguo 11/09/2015, 09:55
Avatar de giuli956  
Fecha de Ingreso: noviembre-2012
Mensajes: 149
Antigüedad: 11 años, 5 meses
Puntos: 1
¿Porque el constructor afuera de la clase?Singleton

Bueno estoy desarrollando el patron singleton en C++ utilizando Dev C++, y lo tengo ya listo, pero quiero aclarar conceptos.

yo tenia el constructor dentro de la clase como privado obviamente y no funcionaba, pero luego encontre en internet:

Código C++:
Ver original
  1. unicaConexion::unicaConexion()
  2. {};

y el metodo publico getInstance tambien fuera de la clase:

Código C++:
Ver original
  1. unicaConexion* unicaConexion::_conexion=0;
  2. unicaConexion* unicaConexion::getInstance(){
  3.                  
  4.                        if (_conexion==0){
  5.                                            _conexion=new unicaConexion;
  6.                                            
  7.                                            cout<<("Es la primera vez que se conecta a mysql")<<endl;
  8.                                            
  9.                        }
  10.                        else{
  11.                                                
  12.                            cout<<("conexion ya realizada")<<endl;
  13.                            
  14.                        };
  15.                        return _conexion;
  16.              };

Porque no puedo tener la clase estatica con todo declarado dentro de ella? y luego el main().
  #2 (permalink)  
Antiguo 11/09/2015, 14:44
 
Fecha de Ingreso: octubre-2014
Ubicación: Madrid
Mensajes: 1.212
Antigüedad: 9 años, 6 meses
Puntos: 204
Respuesta: ¿Porque el constructor afuera de la clase?Singleton

En un patrón singleton, por definición, la única instancia del objeto que puede existir se crea dentro de un método estático del propio objeto:

Código C++:
Ver original
  1. class Singleton
  2. {
  3.   public:
  4.     static Singleton& Instance( )
  5.     {
  6.       static Singleton instance;
  7.       return instance;
  8.     }
  9. }

Nota: Si te ha resultado extraño el valor de retorno del singleton te comento: Devolver un puntero es peligroso porque a alguien le puede entrar la tentación de ponerle un delete, mientras que si el método devuelve una referencia su uso se hace más natural... a nadie se le ocurre hacer un delete a una referencia.

Debido a este motivo y a que no se desea que haya más instancias pululando por la aplicación (por eso se aplica el patrón singleton), los constructores deben ser TODOS privados. El hecho de que sean privados no afecta al método Instance porque, como hemos visto, pertenece a la propia clase, luego tiene acceso sin restricciones a los elementos de la clase.

Por otro lado tenemos que el compilador tiende a crear una versión por defecto del constructor por defecto, constructor copia y operador de asignación. Y digo tiende porque ésto solo sucede bajo ciertas condiciones:

  • No se deben poner las firmas de las funciones en el archivo de cabecera. Si pones explicitamente la declaración del operador o del constructor en la cabecera el compilador se desentiende y es tu responsabilidad implementar la función
  • En el caso de herencia, si la clase base tiene el constructor correspondiente como privado, el compilador no podrá crear la versión del constructor correspondiente en la clase hija.
Y por si con esto no había suficiente, el estándar C++11 añade más causística:
  • Aparece un nuevo tipo de constructor Clase(Clase&&). Si no se declara explícitamente este constructor, el compilador puede intentar crear el constructor copia. Si se declara este constructor, el constructor copia no se implementará.
  • Aparecen dos modificadores nuevos delete y default. El primero especifica que la función correspondiente no existe para la clase en cuestión, en este caso el compilador no creará la versión por defecto. El segundo obliga al compilador a crear la versión por defecto del constructor, aunque alguna de las reglas anteriores le indique lo contrario. Estos dos modificadores no pueden, obviamente, coexistir en la misma función.
Un par de ejemplos para ilustrarnos:


Código C++:
Ver original
  1. // Esta clase dispone de:
  2. //  * Constrtuctor por defecto
  3. //  * Constructor copia
  4. //  * Operador de asignación
  5.  
  6. class Test1
  7. {
  8. };
  9.  
  10.  
  11. // Si no se implementa el constructor por defecto, se producirá
  12. // un error al intentar llamarlo. Aunque no se pueda probar,
  13. // esta clase cuenta con constructor copia y operador de asignación
  14.  
  15. class Test2
  16. {
  17.   public:
  18.     Test2();
  19.  
  20. };
  21.  
  22.  
  23. // Las 3 firmas son privadas, luego no podrán ser llamadas desde fuera
  24. // de la clase. No obstante, si éstas funciones no se implementan, tampoco
  25. // podrán ser llamadas desde la propia clase
  26.  
  27. class Test3
  28. {
  29.     Test3();
  30.     Test3(const Test3&);
  31.     Test3& operator=(const Test3&);
  32.  
  33. };
  34.  
  35.  
  36. // Adivina... no se pueden usar los constructores porque intentarán llamar al constructor correspondiente de Test3... que es privado.
  37.  
  38. class Test4 : public Test3
  39.  
  40. {
  41.    
  42.  
  43. };
  44.  
  45.  
  46.  
  47. // Válido para C++11 en adelante
  48. // El constructor por defecto queda anulado
  49. // Se implementa el nuevo constructor de C++11
  50. // Se obliga al compilador a crear el código por defecto para el constructor copia
  51. // Si no se indica, el compilador no creará este constructor por existir el otro.
  52. class Test5
  53. {
  54.   public:
  55.      Test5() = delete;
  56.      
  57.      Test5(Test5&&){ }
  58.      Test5(const Test5&) = default;
  59. };

Dicho esto, qué forma ha de tener (o debería tener) un singleton? Bueno, salvo que necesites añadir más requisitos (como que la cadena de singleton se borren de una forma determinada al finalizar el programa para liberar recursos por ejemplo) debería tener esta forma:

Código C++:
Ver original
  1. class Singleton
  2. {
  3.   public:
  4.  
  5.     static Singleton& Instance()
  6.     {
  7.       static Singleton instance;
  8.       return instance;
  9.     }
  10.  
  11.   private:
  12.     Singleton(); // No olvides implementar esta función
  13.     Singleton(const Singleton&); // No hace falta implementarla
  14.     Singleton(const Singleton&) = delete; // Opción 2 (C++11)
  15.     Singleton& operator=(const Singleton&); // No hace falta implementarla
  16.     Singleton& operator=(const Singleton&) = delete; // Opción 2 (C++11)
  17. }

Por supuesto, la implementación puede estar fuera de la clase:

Código C++:
Ver original
  1. class Singleton
  2. {
  3.   public:
  4.  
  5.     static Singleton& Instance();
  6.     {
  7.       static Singleton instance;
  8.       return instance;
  9.     }
  10.  
  11.   private:
  12.     Singleton(); // No olvides implementar esta función
  13.     Singleton(const Singleton&) = delete;
  14.     Singleton& operator=(const Singleton&) = delete;
  15. }
  16.  
  17. // ...en otro fichero o donde quieras...
  18. Singleton::Singleton()
  19. {
  20.   // ...
  21. }
  22.  
  23. Singleton& Singleton::Instance()
  24. {
  25.   static Singleton instance;
  26.   return instance;
  27. }

PD.:

Cita:
Iniciado por giuli956 Ver Mensaje
Bueno estoy desarrollando el patron singleton en C++ utilizando Dev C++, y lo tengo ya listo, pero quiero aclarar conceptos.

yo tenia el constructor dentro de la clase como privado obviamente y no funcionaba, pero luego encontre en internet:

Código C++:
Ver original
  1. unicaConexion::unicaConexion()
  2. {};
Ese ';' detrás de las llaves va a dar error de compilación. Y lo mismo te digo sobre el otro punto y coma que está justo después de salir de la función getInstance

Un saludo.

Etiquetas: constructor, funcion, int
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta




La zona horaria es GMT -6. Ahora son las 20:26.