Por qué es necesaria la declaración directa en C ++
El compilador quiere asegurarse de que no haya cometido errores ortográficos o haya pasado un número incorrecto de argumentos a la función. Por lo tanto, insiste en que primero ve una declaración de 'agregar' (o cualquier otro tipo, clase o función) antes de usarlo.
Esto realmente solo permite que el compilador haga un mejor trabajo de validación del código, y le permite ordenar los cabos sueltos para que pueda producir un archivo de objeto ordenado. Si no tuviera que reenviar las declaraciones, el compilador produciría un archivo de objeto que tendría que contener información sobre todas las posibles suposiciones sobre cuál podría ser la función 'agregar'. Y el enlazador tendría que contener una lógica muy inteligente para tratar de determinar qué 'agregar' realmente pretendía llamar, cuando la función 'agregar' puede vivir en un archivo de objeto diferente, el enlazador se une con el que usa agregar para producir un dll o exe. Es posible que el enlazador obtenga el complemento incorrecto. Supongamos que desea usar int add (int a, float b), pero accidentalmente olvidó escribirlo, pero el vinculador encontró un int add ya existente (int a, int b) y pensé que era el correcto y usé eso en su lugar. Su código se compilaría, pero no estaría haciendo lo que esperaba.
Entonces, solo para mantener las cosas explícitas y evitar las conjeturas, etc., el compilador insiste en que declares todo antes de usarlo.
Diferencia entre declaración y definición
Por otro lado, es importante saber la diferencia entre una declaración y una definición. Una declaración solo proporciona suficiente código para mostrar cómo se ve algo, así que para una función, este es el tipo de retorno, la convención de llamada, el nombre del método, los argumentos y sus tipos. Pero el código para el método no es obligatorio. Para una definición, necesita la declaración y también el código para la función también.
Cómo las declaraciones directas pueden reducir significativamente los tiempos de compilación
Puede obtener la declaración de una función en su archivo actual .cpp o .h # incluyendo el encabezado que ya contiene una declaración de la función. Sin embargo, esto puede ralentizar su compilación, especialmente si #incluye un encabezado en un .h en lugar de .cpp de su programa, ya que todo lo que # incluye el .h que está escribiendo terminaría # incluyendo todos los encabezados escribiste #incluye también. De repente, el compilador tiene #incluidas páginas y páginas de código que necesita compilar incluso cuando solo desea utilizar una o dos funciones. Para evitar esto, puede usar una declaración directa y simplemente escribir la declaración de la función usted mismo en la parte superior del archivo. Si solo usa algunas funciones, esto realmente puede hacer que sus compilaciones sean más rápidas en comparación con #incluir siempre el encabezado. Para proyectos realmente grandes,
Romper referencias cíclicas donde dos definiciones se usan
Además, las declaraciones directas pueden ayudarlo a romper los ciclos. Aquí es donde dos funciones intentan usarse entre sí. Cuando esto sucede (y es una cosa perfectamente válida), puede #incluir un archivo de encabezado, pero ese archivo de encabezado intenta # incluir el archivo de encabezado que está escribiendo actualmente ... que luego # incluye el otro encabezado , que incluye el que estás escribiendo. Estás atrapado en una situación de huevo y gallina con cada archivo de encabezado intentando #incluir el otro. Para resolver esto, puede declarar hacia adelante las partes que necesita en uno de los archivos y dejar el #include fuera de ese archivo.
P.ej:
File Car.h
#include "Wheel.h" // Include Wheel's definition so it can be used in Car.
#include <vector>
class Car
{
std::vector<Wheel> wheels;
};
File Wheel.h
Hmm ... aquí se requiere la declaración de Car ya que Wheel tiene un puntero a un Car, pero Car.h no se puede incluir aquí ya que daría lugar a un error del compilador. Si se incluye Car.h, eso trataría de incluir Wheel.h, que incluiría Car.h, que incluiría Wheel.h, y esto continuaría para siempre, por lo que el compilador genera un error. La solución es reenviar declarar Car en su lugar:
class Car; // forward declaration
class Wheel
{
Car* car;
};
Si la clase Wheel tuviera métodos que necesitaran llamar métodos de auto, esos métodos podrían definirse en Wheel.cpp y Wheel.cpp ahora puede incluir Car.h sin causar un ciclo.