2009-10-14 10 views
8

Ist der folgende Code legal C++ oder nicht?Deklarieren, aber nicht definieren innere Struktur/Klasse - legal C++ oder nicht?

class Foo 
{ 
    class Bar; 

    void HaveADrink(Bar &bar); 
    void PayForDrinks(Bar &bar); 

    public: 
    void VisitABar(int drinks); 
}; 

class Foo::Bar 
{ 
    public: 
    int countDrinks; 
}; 

void Foo::HaveADrink(Bar &bar) 
{ 
    bar.countDrinks++; 
} 
void Foo::PayForDrinks(Bar &bar) 
{ 
    bar.countDrinks = 0; 
} 
void Foo::VisitABar(int drinks) 
{ 
    Bar bar; 
    for (int i=0; i<drinks; i++) HaveADrink(bar); 
    PayForDrinks(bar); 
} 

Sowohl Visual C++ und GCC akzeptiert, jedoch scheint der Code etwas seltsam für mich, und ich würde es hassen, es von einem zukünftigen Compiler verweigert zu haben.

Noch scheint das Muster nützlich zu sein, um Kompilierungszeitabhängigkeiten zu reduzieren - ich benutze es häufig, um Strukturen zu deklarieren, die verwendet werden, um einige "Kontext" (ein Bündel von Variablen) zu übergeben, die zwischen einigen wenigen Funktionen geteilt werden in der gleichen CPP-Datei, und auf diese Weise muss ich nicht die "Kontext" -Definition in die öffentliche Schnittstelle einführen.

+0

Ich bin gerade dabei, ein paar Kontext-Klassen zu erstellen, also bin ich auch interessiert. BTW, machen Sie countDrinks öffentlich zugänglich. – stefaanv

+0

Habe ich recht, wenn ich annehme, dass Sie sich auf die 'class Foo :: Bar' Definition beziehen? – MSalters

Antwort

10

legal und in der Tat nützlich, um Implementierungsdetails nach außen zu verbergen.

9

[Bearbeiten] ich ursprünglich gesagt, dies das „Pimpl Idiom“ ist: http://c2.com/cgi/wiki?PimplIdiom aber ich stimme zu, dass dies nur ein Teil Pimpl ist im Begriff ist. Diese Technik wird von pimpl verwendet.

Sie sind "Weiterleiten" Klasse Bar innerhalb der Klasse Foo. Tadellos legal, solange du nichts innerhalb des Definino von Foo machst, das die Größe von Bar erfordern würde. Sie können auf einen Balken mit einem Zeiger oder einer Referenz verweisen (Balken * oder Balken &), aber wenn Sie ein Datenelement in Foo wie dem folgenden deklarieren:

privat: Bar _bar;

Es würde nicht funktionieren. Der Grund dafür ist, dass die Definition von Foo ausreichen muss, um die Größe von Foo zu bestimmen. Da die Größe von Bar innerhalb der Definition von Foo unbekannt ist, würde die Größe von Foo unbestimmt werden. Aber die Verwendung eines Zeigers würde funktionieren:

privat: Bar * _bar;

Da die Größe des Zeigers gleich ist und somit bekannt ist, unabhängig davon, wie Bar später definiert wird.

+2

Nun, es ist nicht _exactly_ die Pimpl-Idiom (es gibt keine Pimpl in seinem Code), aber Sie haben Recht - im Wesentlichen ist es. +1 – sbi

+1

Es bezieht sich nur auf die pimpl, da es mehr über den Umfang eines Kontextes ist, wo die pimpl die vollständige Implementierung Ihrer Klasse ist. Aber Sie haben recht: Sie können nur einen Zeiger deklarieren. Tun Sie sich selbst einen Gefallen und verwenden Sie den entsprechenden Smart Pointer. – stefaanv

+0

Es ist definitiv nicht PIMPL. Es gibt keine Implementierung in Bar. –