Creo que la limitación que ha considerado no está relacionada con la semántica (¿por qué debería cambiar algo si se definiera la inicialización en el mismo archivo?) sino más bien con el modelo de compilación de C ++ que, por razones de compatibilidad con versiones anteriores, no se puede cambiar fácilmente porque se volvería demasiado complejo (admitir un nuevo modelo de compilación y el existente al mismo tiempo) o no permitiría compilar el código existente (introduciendo un nuevo modelo de compilación y eliminando el existente).
El modelo de compilación de C ++ se deriva de C, en el que se importan las declaraciones a un archivo de origen al incluir los archivos (encabezado). De esta manera, el compilador ve exactamente un archivo fuente grande, que contiene todos los archivos incluidos, y todos los archivos incluidos de esos archivos, recursivamente. Esto tiene una gran ventaja de IMO, a saber, que hace que el compilador sea más fácil de implementar. Por supuesto, puede escribir cualquier cosa en los archivos incluidos, es decir, tanto declaraciones como definiciones. Solo es una buena práctica colocar declaraciones en archivos de encabezado y definiciones en archivos .c o .cpp.
Por otro lado, es posible tener un modelo de compilación en el que el compilador sabe muy bien si está importando la declaración de un símbolo global que está definido en otro módulo , o si está compilando la definición de un símbolo global proporcionado por el módulo actual . Solo en este último caso, el compilador debe poner este símbolo (por ejemplo, una variable) en el actual
archivo de objeto.
Por ejemplo, en GNU Pascal puede escribir una unidad a
en un archivo a.pas
gusta esto:
unit a;
interface
var MyStaticVariable: Integer;
implementation
begin
MyStaticVariable := 0
end.
donde la variable global se declara e inicializa en el mismo archivo fuente.
Luego puedes tener diferentes unidades que importan y usan la variable global
MyStaticVariable
, por ej. una unidad b ( b.pas
):
unit b;
interface
uses a;
procedure PrintB;
implementation
procedure PrintB;
begin
Inc(MyStaticVariable);
WriteLn(MyStaticVariable)
end;
end.
y una unidad c ( c.pas
):
unit c;
interface
uses a;
procedure PrintC;
implementation
procedure PrintC;
begin
Inc(MyStaticVariable);
WriteLn(MyStaticVariable)
end;
end.
Finalmente, puedes usar las unidades byc en un programa principal m.pas
:
program M;
uses b, c;
begin
PrintB;
PrintC;
PrintB
end.
Puedes compilar estos archivos por separado:
$ gpc -c a.pas
$ gpc -c b.pas
$ gpc -c c.pas
$ gpc -c m.pas
y luego genere un ejecutable con:
$ gpc -o m m.o a.o b.o c.o
y ejecútalo:
$ ./m
1
2
3
El truco aquí es que cuando el compilador ve una directiva usa en un módulo de programa (por ejemplo, usa a en b.pas), no incluye el archivo .pas correspondiente,
pero busca un archivo .gpi, es decir, un archivo de interfaz precompilado
(Consulte la documentación ).
Estos archivos .gpi
son generados por el compilador junto con los archivos .o
cuando se compila cada módulo.
Por lo tanto, el símbolo global MyStaticVariable
solo se define una vez en el archivo de objeto a.o
.
Java funciona de una manera similar: cuando el compilador importa una clase A a la clase B, busca el archivo de clase para A y no necesita el archivo A.java
. Por lo tanto, todas las definiciones e inicializaciones para la clase A se pueden colocar en un archivo fuente.
Volviendo a C ++, la razón por la que en C ++ tiene que definir miembros de datos estáticos en un archivo separado está más relacionada con el modelo de compilación de C ++ que con las limitaciones impuestas por el vinculador u otras herramientas utilizadas por el compilador.
En C ++, importar algunos símbolos significa construir su declaración como parte de
La unidad de compilación actual. Esto es muy importante, entre otras cosas,
Por la forma en que se compilan las plantillas. Pero esto implica que no puede / no debe definir ningún símbolo global (funciones, variables, métodos, miembros de datos estáticos) en un archivo incluido, de lo contrario estos símbolos podrían ser
Se define de forma múltiple en los archivos de objetos compilados.