4. Constructores

Inicializaciones de Objetos.
Los constructores son funciones miembro especiales que sirven para inicializar un objeto de una determinada clase al mismo tiempo que se declara, vimos para el ejemplo del objeto tv14p que el volumen y el canal tenían basura al comenzar a utilizar el objeto.
Es por eso que se recomienda que el constructor CONFIGURE el valor de las propiedades al momento de crear el objeto, de manera de evitar  indefiniciones de la misma.
En caso de NO ser necesario asignar valores a propiedades privadas al momento de crear el objeto, por que NO existan propiedades privadas o por que la lógica del problema no lo necesite NO es necesario definir un  Constructor, el compilador lo hace solo y de manera automática y NO aparece ningún error por falta del mismo.
Los constructores no se pueden llamar explícitamente como si fueran funciones miembro regulares. Solo se ejecutan una vez, cuando se crea un nuevo objeto de esa clase.
Sería algo parecido a poner:
int a=20; /* defino el tipo e inicializo */

Los constructores :

  • tienen el mismo nombre que la clase, es fácil identificarlos
  • NO retornan ningún valor
  • NO pueden ser heredados. Además
  • deben ser públicos,
No tendría ningún sentido declarar un constructor como privado, ya que siempre se usan desde el exterior de la clase al crear el objeto , tampoco como protegido, ya que no puede ser heredado, esto se verá mas adelante
Añadamos un constructor a nuestra clase pareja:

  • # include <iostream>
    using namespace std;
    class Televisor 
    {//Definimos la plantilla de propiedades y métodos de la clase Televisor.
      bool m_bEncedido; //miembros o propiedades de la clase, es privado
      unsigned int m_uiCanal;// la m_ indica que es un miembro o propiedad
      unsigned int m_uiVolumen; //miembro o propiedad 
    
      public: //los metodos y propiedades que continúan línea abajo son públicos
      //métodos publicos
      Televisor(){m_bEncedido=false;m_uiCanal=1;m_uiVolumen=0;}//Constructor
      void Encender() {m_bEncedido=true;};//Defino el método dentro de la clase
      void Apagar(){m_bEncedido=false;};//Defino el método dentro de la clase
      bool Estado(){return m_bEncedido;}    
      bool ModificarVolumen( unsigned int  uiVolumen);//método
      bool ModificarCanal ( unsigned int  uiCanal);//método
      unsigned int ConsultaVolumen ();//método
      unsigned int ConsultaCanal ();//método
    } ; //Fin de definición de la clase Televisor
    
    //Metodo de cambia de Canal,definido Fuera de Clase por eso el op. de ambito ::
    bool Televisor::ModificarCanal ( unsigned int  uiCanal)
    {
      if (m_bEncedido)
      	{m_uiCanal=uiCanal;
      	return true;}
      else return false;    
    }
    
    //Metodo Cambia el Volumen,definido Fuera de Clase por eso el op. de ambito ::    
    bool Televisor::ModificarVolumen ( unsigned int  uiVolumen)
    {
      if (m_bEncedido)
        {m_uiVolumen=uiVolumen;
        return true;}
      else return false;    
    }
    
    //Metodo Consulta el Volumen,definido Fuera de Clase por eso el op. de ambito ::    
    unsigned int Televisor :: ConsultaVolumen ()
    {return m_uiVolumen;}
    
    //Metodo Consulta el Canal,,definido Fuera de Clase por eso el op. de ambito ::    
    unsigned int Televisor :: ConsultaCanal ()        
    {return m_uiCanal;}
    
    //Comienza la Funcion main------------------------        
    int main()
    { 
      char opcion; int volumen, canal
      Televisor tv14p; //Instancio el objeto tv14p con la clase Televisor
      do
      {
      cout << " Indique la acción :" << endl;
      cout << " 1 para Encender" << endl;
      cout << " 0 para Apagar" << endl;
      cout << " 2 Para modificar el Volumen" << endl;
      cout << " 3 Para modificar el Canal "<< endl;    
      cout << " Otra tecla para Salir "<< endl;    
      cin >> opcion;
      switch (opcion)
         {
         case '1': tv14p.Encender();break;//Enciendo el televisor 
         case '0': tv14p.Apagar();break ;//Apago el televisor 
         case '2': cout << "EL volumen esta en: "<< tv14p.ConsultaVolumen();
                   cout << "Ingrese el nuevo valor del Volumen: "<<endl;
                   cin >> volumen;
         					 tv14p.ModificarVolumen(volumen);
         					 break;
         case '3': 
          cout << "EL Canal actual esta en: " <<Tv14p.ConsultaCanal();
          cout << "Ingrese el nuevo valor del Canal: " << endl;
          cin >> canal;
          tv14p.ModificarCanal(canal);break;
         case '4': 
          cout<<"El Estado del TV es: "<<tv14p.Estado()<<endl;
        cout<<"El canal al inicio es: "<<tv14p.ConsultaCanal()<<endl;
        cout<<"El volumen al inicio es: "<<tv14p.ConsultaVolumen()<<endl;
          
         }
      }while ('0'==opcion||'1'==opcion||'2'==opcion||'3'==opcion ||'4'==opcion);    
      return 0;
    
    }
    
Si una clase posee constructor, será llamado siempre que se declare un objeto de esa clase, y si requiere argumentos, es obligatorio suministrarlos.
En el ejemplo anterior  nuestro constructor NO recibe argumento.
Se declara en la línea 11 dentro de la clase y se ejecuta cuando se crea el objeto en la línea 51.
Tambíen se podría incorporar OTRO constructor, definiendo valores para las propiedades del objeto, por ejemplo:

    •  Televisor(){m_bEncedido=true;m_uiCanal=1;m_uiVolumen=0;}//Constructor
    •  Televisor(bool on_off, int canal, int volumen) {m_bEncedido=on_off;m_uiCanal=canal;m_uiVolumen=volumen;}//Constructor con 3 argumentos.
En el primer caso , se podría instanciar el objeto :

Televisor tv14p(true,10,5); //Instancio el objeto tv14p con la clase Televisor

Por ejemplo, las siguientes declaraciones son ilegales:

Televisor tv14p(true,10);
Televisor tv14p();

La primer  declaración esta mal por que los constructores  para nuestro caso reciben cero argumento o tres argumentos. Por supuesto los tipos de los argumentos pasados al constructor deben respetar el tipo de datos.
La segunda es ilegal por otro motivo más complejo. Aunque existiese un constructor sin parámetros, no se debe usar esta forma para declarar el objeto, ya que el compilador lo considera como la declaración de un prototipo de una funciónque devuelve un objeto de tipo "Televisor" y no admite parámetros. Cuando se use un constructor sin parámetros para declarar un objeto no se deben escribir los paréntesis.
Cuando no especifiquemos un constructor para una clase, el compilador crea uno por defecto sin argumentos. Por eso en los ejemplos anteriores funcionaba correctamente.
Cuando se crean objetos locales, los datos miembros no se inicializarían, contendrían la "basura" que hubiese en la memoria asignada al objeto al crear el compilador un constructor por defecto esto no sucede. Si se trata de objetos globales, los datos miembros se inicializan a cero.
Para declarar objetos usando el constructor por defecto o un constructor que hayamos declarado sin parámetros no se debe usar el paréntesis

Observaciones:

Se pueden definir los Constructores de 2 maneras distintas, para el caso de la clase "Televisor":

Forma 1: (Ya mostrada)
Televisor(bool on_off, int canal, int volumen) {m_bEncedido=on_off;m_uiCanal=canal;m_uiVolumen=volumen;}//Constructor con 3 argumentos.

Forma 2:

Podemos sustituir el constructor por:

Televisor(bool on_off, int canal, int volumen):m_bEncedido(on_off),m_uiCanal(canal),m_uiVolumen(volumen){}//Constructor con 3 argumentos.
Que es un anuncio - Gestion.Org
Conclusiones:
  • El constructor es Public !! ( no tendría sentido otro tipo de acceso)
  • El constructor NO TIENE TIPO
  • El nombre del Constructor es IGUAL al de la CLASE




Sobrecarga de constructores

Como cualquier otra función, un constructor también se puede sobrecargar con diferentes versiones tomando diferentes parámetros: con un número diferente de parámetros y / o parámetros de diferentes tipos.
El compilador llamará automáticamente a aquel cuyos parámetros coincidan con los argumentos:

Televisor(bool on_off, int canal, int volumen){m_bEncedido=on_off;m_uiCanal=canal;m_uiVolumen=volumen;}//Constructor
Televisor(){m_bEncedido=false;m_uiCanal=1;m_uiVolumen=0;}//Constructor
Ejemplo de Sobrecarga de Funciones.