Disponible la nueva versión "donationware" 7.3 de OrganiZATOR
Descubre un nuevo concepto en el manejo de la información.
La mejor ayuda para sobrevivir en la moderna jungla de datos la tienes aquí.

Curso C++

[Home]  [Inicio]  [Índice]


Ejemplo

Se muestra la influencia y comportamiento de los constructores por defecto, explícitos e implícitos, ofreciendo diversas combinaciones de código ejecutable sobre el supuesto mostrado en la página principal.

El primer caso analizado corresponde exactamente con el código propuesto:

#include <iostream>
using namespace std;

struct Nombre {
  char* nomb;
};

struct Equipo {
  Nombre nm;
  size_t sz;
};

struct Liga {
  int year;
  char categoria;
  Nombre nLiga;
  Equipo equipos[10];
};

int main() {     // ===========
  Liga primDiv;
  cout << "R1: " << primDiv.nLiga.nomb << endl;
  cout << "R2: " << primDiv.equipos[0].nm.nomb << endl;
  cout << "R3: " << primDiv.equipos[0].sz << endl;
  cout << "R4: " << primDiv.equipos[9].nm.nomb << endl;
  cout << "R5: " << primDiv.equipos[9].sz << endl;
  return 0;
}

Comentario

El programa compila sin dificultad pero presenta un error fatal de runtime. La razón son las salidas R2 y R4, que intentan mostrar la cadena de caracteres señalada por el puntero Nombre::nomb. Este tipo no ha sido inicializado por el constructor por defecto de Nombre, por lo que su contenido es basura y señala a algún punto arbitrario inaccesible por el programa.

Para resolver el problema, añadimos un constructor por defecto a la clase Nombre que queda con el siguiente diseño (el resto permanece idéntico):

struct Nombre {
  char* nomb;
  Nombre() { nomb = "Anonimo"; }
};

El nuevo diseño produce el siguiente resultado:

R1: Anonimo
R2: Anonimo
R3: 8
R4: Anonimo
R5: 5205190

Los valores obtenido en R3 y R5 para el miembro sz de los elementos primero y décimo del la matriz equipos son basura, ya que size_t es un tipo básico. Así mismo puede comprobarse que ha sido invocado el constructor de Equipo para cada uno de los miembros de la referida matriz.

Finalmente investigamos el efecto de incluir un constructor explícito para la clase Liga. El programa queda con el siguiente diseño:

#include <iostream>
using namespace std;

struct Nombre {
  char* nomb;
  Nombre() { nomb = "Anonimo"; } // constructor
};

struct Equipo {
  Nombre nm;
  size_t sz;
};

struct Liga {
  int year;
  char categoria;
  Nombre nLiga;
  Equipo equipos[10];
  Liga() {       // constructor
    nLiga.nomb = "Primera division";
  }
};

int main() {     // ===========
  Liga primDiv;
  cout << "R1: " << primDiv.nLiga.nomb << endl;
  cout << "R2: " << primDiv.equipos[0].nm.nomb << endl;
  cout << "R3: " << primDiv.equipos[0].sz << endl;
  cout << "R4: " << primDiv.equipos[9].nm.nomb << endl;
  cout << "R5: " << primDiv.equipos[9].sz << endl;
  return 0;
}

Las salidas:

R1: Primera division
R2: Anonimo
R3: 8
R4: Anonimo
R5: 4205198

Comentario

Puede verse como las circunstancias permanecen inalteradas para los miembros simples que no disponen de inicialización explícita. Cómo la inclusión del constructor explícito y sin argumentos Liga::Liga(), realiza su cometido con el miembro Liga::nLiga, y cómo el hecho de haber omitido cualquier referencia explícita a la inicialización del miembro Liga::equipos no ha impedido que esta función continúe siendo invocada automáticamente por el compilador.