una resueltos programacion poo orientada objetos estructura ejercicios ejemplo dentro codigo clases clase c++

resueltos - poo c++



C++ Forward declarando clases dentro de las clases (4)

Además de eso, cuando tengo la necesidad de declarar clases anidadas, tiendo a oler un poco de mal diseño en mi código, el truco que uso es:

// Foo.h class Foo { class Bar { }; }; class Foobar : public Foo::Bar {}; // Zoo.h /* Fwd declare */ class FooBar;

La siguiente pieza simple de código se compila, aunque no entiendo por qué:

class C { class B; class A { B getB() { return B(); } }; class B { }; }; int main(int, char**) { return 0; }

Si luego comento las cosas de " class C ", de modo que la declaración directa de B , la definición de A y la definición de B ya no estén anidadas dentro de una clase, el código no se compila, ya que B es de un tipo incompleto :

main.cpp: In member function ''B A::getB()'': main.cpp:6: error: return type ''struct B'' is incomplete main.cpp:6: error: invalid use of incomplete type ''struct B'' main.cpp:3: error: forward declaration of ''struct B''

Entiendo lo que significa que un tipo esté incompleto, es decir, que aún no se ha definido y, por lo tanto, el compilador no puede saber cuánto espacio puede asignar para él. Pero, ¿por qué B no se considera incompleta en el código anterior, donde A y B se declaran y definen dentro de C ?


Creo que esto es una consecuencia de [basic.scope.class] :

El alcance potencial de un nombre declarado en una clase consiste no solo en la región declarativa que sigue al punto de declaración del nombre, sino también en todos los cuerpos de función, argumentos predeterminados, especificaciones de excepción y inicializadores brace o iguales de no estáticos miembros de datos en esa clase (incluyendo cosas así en clases anidadas).

Es decir, el alcance de la declaración completa de B incluye el cuerpo de la función miembro de la clase anidada:

class C { class B; // (1) class A { B getB() { return B(); // both (1) and (2) in scope here // since (2) is the complete type declaration, // this is perfectly fine } }; class B { // (2) }; };

En comparación, si C fuera un espacio de nombres en lugar de una clase, el alcance de la declaración completa de la clase B no se extendería a A::getB() . La única declaración visible sería la declaración directa de B que etiqueté (1) , por lo que B() sería la construcción de un tipo incompleto allí.


El cuerpo de una función miembro en línea no se procesa hasta que la definición de clase se haya procesado completamente.

Por lo tanto, puede utilizar:

class A { class B; B getB() { return B(); } class B {}; };

Esto también permite que las variables de miembro que aún no se declararon se usen en la definición de función de miembro en línea.

class Foo { int getBar() { return bar; } int bar; };

Supongo que la misma lógica se extiende a las definiciones en línea de las funciones miembro de las clases anidadas, es decir, no se procesan hasta que la definición de la clase contenedora se procesa por completo.

PD No puedo ubicar rápidamente la referencia en el estándar que verificaría mi reclamo.

PS 2 La respuesta de Barry tiene la referencia en el estándar que hace que el código en la pregunta sea válido.


El estándar es explícito al exigir que el cuerpo del método se interprete después de la clase que lo encierra.

Por lo tanto, al momento de evaluar el cuerpo de C::A::getB() , A , B y C son todos tipos completos.