Vraag C ++ Forward Declarerende klassen binnen klassen


Het volgende eenvoudige stuk code compileert, hoewel ik niet begrijp waarom:

class C {
    class B;

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

    class B {
    };
};

int main(int, char**)
{
    return 0;
}

Als ik dan de "class C"dingen, zodat de voorwaartse verklaring van B, de definitie van A en de definitie van B zijn niet langer genest binnen een klasse, de code compileert niet, sinds B is van een incompleet type:

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'

Ik begrijp wat het betekent voor een type om onvolledig te zijn, namelijk dat het nog niet is gedefinieerd en dus kan de compiler onmogelijk weten hoeveel ruimte hij daarvoor moet reserveren. Maar waarom is dat zo B niet als onvolledig beschouwd in de bovenstaande code, waar A en B zijn beide gedeclareerd en gedefinieerd binnenin C?


17
2018-03-10 20:35


oorsprong


antwoorden:


Ik geloof dat dit een gevolg is van [Basic.scope.class]:

De potentiële reikwijdte van een naam die in een klasse wordt aangegeven, bestaat niet alleen uit de declaratieve regio die volgt op de   punt van de declaratie, maar ook van alle functies, standaardargumenten, uitzondering-specificaties, en brace-of-gelijke-initialiseerders van niet-statische gegevensleden in die klasse (inclusief dergelijke items in genest   klassen).

Dat wil zeggen, de reikwijdte van de vol verklaring van B bevat de hoofdtekst van de lidfunctie van de geneste klasse:

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)
    };
};

Ter vergelijking, als C waren een naamruimte in plaats van een klasse, de reikwijdte van de volledige verklaring van klasse B zou niet in gaan A::getB(). De enige zichtbare verklaring zou de forward-declaratie van zijn B die ik heb gelabeld (1) - zo B() zou daar de constructie zijn van een incompleet type.


10
2018-03-10 21:41



De hoofdtekst van een inline-lidfunctie wordt pas verwerkt nadat de klassendefinitie volledig is verwerkt.

Vandaar dat u kunt gebruiken:

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

   class B {};
};

Dat laat ook lidvariabelen toe die nog niet zijn gedeclareerd om te worden gebruikt bij definitie van inline-lidfuncties.

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

   int bar;
};

Ik veronderstel dat dezelfde logica wordt uitgebreid tot inline-definities van lidfuncties van geneste klassen, dat wil zeggen dat ze niet worden verwerkt totdat de definitie van de klassenklasse volledig is verwerkt.

PS Ik kan de verwijzing in de standaard niet snel vinden om mijn claim te verifiëren.

PS 2  Het antwoord van Barry heeft de referentie in de standaard die de code in de vraag geldig maakt.


9
2018-03-10 20:56



De standaard is expliciet in het verplicht stellen dat het lichaam van de methode wordt geïnterpreteerd na de klasse die het bevat.

Dus op het moment van evaluatie van het lichaam van C::A::getB(), A, B en C zijn alle complete typen.


5
2018-03-10 20:54



Daarnaast heb ik de behoefte om geneste klassen te declareren. Ik ruik een of ander slecht ontwerp in mijn code, de truc die ik gebruik is:

// Foo.h
class Foo {
    class Bar {
    };
};
class Foobar : public Foo::Bar {};


// Zoo.h
/* Fwd declare */
class FooBar;

0
2018-05-08 14:01