Para instanciar un dato el compilador debe saber cuánto ocupa. El compilador no sabe cuánto ocupa un dato hasta que éste se define; una definición de objeto se completa al cerrar sus llaves:
struct nodo // Esto declara el objeto
{
int dato;
}; // Aquí el objeto está definido.
Sabemos que el objeto nodo
ocupará lo mismo que ocupe un int
, que es su único miembro, si añadimos un objeto del mismo tipo a la definición obtendremos un error:
struct nodo // Esto declara el objeto
{
int dato;
nodo siguiente; // Error, 'nodo' no está definido!
}; // Aquí el objeto está definido.
Obtenemos el error porque en el momento en que queremos usar nodo
, su definición aún no ha acabado y el compilador no podrá saber cuánto ocupa.
Pero si usamos punteros el problema se soluciona, el compilador siempre sabe lo que ocupa un puntero a un dato arbitrario, ¡incluso punteros a datos que aún no están definidos!
struct nodo // Esto declara el objeto
{
int dato;
nodo *siguiente; // Aquí aún no sabe lo que es 'nodo', pero sabe que puede apuntar a ello
}; // Aquí el objeto está definido.
Pero el puntero no es el único dato que tiene esta característica, también puedes referenciar objetos sin definir:
struct nodo // Esto declara el objeto
{
int dato;
nodo &siguiente; // Aquí aún no sabe lo que es 'nodo', pero sabe que puede referenciar a ello
}; // Aquí el objeto está definido.
El problema es que las referencias deben referenciar algo, los punteros no (Lee este hilo para saber más del tema), así que aunque la estructura anterior compile, no puede ser instanciada:
struct nodo // Esto declara el objeto
{
int dato;
nodo &siguiente; // Aquí aún no sabe lo que es 'nodo', pero sabe que puede referenciar a ello
}; // Aquí el objeto está definido.
int main()
{
nodo n; // Error, 'n.siguiente' debe ser inicializado
return 0;
}
Ahora podemos responder a la pregunta "¿Por qué se necesitan punteros para hacer que un campo de un struct apunte hacia un struct del mismo tipo?":
Porque no se puede usar una instancia (ya que el objeto no está definido) ni se puede usar una referencia (porque requiere inicialización), así pues sólo es posible usar punteros.