2009-10-14 6 views
8

Le code suivant est-il légal C++ ou non?Déclarez mais ne définissez pas struct/class interne - juridique C++ ou non?

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

Visual C++ et GCC accepte, mais le code me semble un peu étrange et je ne voudrais pas l'avoir refusée par un compilateur futur.

Néanmoins, le modèle me semble utile pour réduire les dépendances de temps de compilation - je l'utilise souvent pour déclarer des structures qui sont utilisées pour passer un "contexte" (un groupe de variables) partagées par quelques fonctions dans le même fichier cpp, et de cette façon je n'ai pas besoin d'introduire la définition de "contexte" dans l'interface publique.

+0

Je suis juste en train de faire quelques classes de contexte, donc ça m'intéresse aussi. BTW, rendre countDrinks accessible au public. – stefaanv

+0

Ai-je raison de supposer que vous faites référence à la définition de 'class Foo :: Bar'? – MSalters

Répondre

10

juridique, et en effet utile pour cacher les détails de l'implémentation au monde extérieur.

9

[modifier] je l'ai dit à l'origine ce fut le « idiome Pimpl »: http://c2.com/cgi/wiki?PimplIdiom mais je suis d'accord que cela fait simplement partie de Pimpl est sur le point. Cette technique est utilisée par pimpl.

Vous "retrouvez" la classe Bar à l'intérieur de la classe Foo. Parfaitement légal tant que vous ne faites rien à l'intérieur du definigino de Foo qui nécessiterait le sizeof Bar. Vous pouvez référencer la barre à l'aide du pointeur ou de la référence (Bar * ou Barre &), mais si vous déclarez un membre de données dans Foo, comme ceci:

private: Bar _bar;

Cela ne fonctionnerait pas. La raison en est que la définition de Foo doit être suffisante pour déterminer la taille de Foo. Puisque la taille de Bar est inconnue dans la définition de Foo, cela rendrait la taille de Foo indéterminée. Mais l'utilisation d'un pointeur fonctionnerait:

privée: Bar * _bar; Parce que la taille du pointeur est la même, et donc connue, indépendamment de la façon dont Bar sera défini plus tard.

+2

Eh bien, ce n'est pas _ exactement_ l'idiome de pimpl (il n'y a pas de pimpl dans son code), mais vous avez raison - c'est essentiellement le cas. +1 – sbi

+1

C'est uniquement lié à pimpl, puisqu'il s'agit plus de la portée d'un contexte, où pimpl est l'implémentation complète de votre classe. Mais vous avez raison: vous ne pouvez déclarer un pointeur que lorsque vous le faites. Faites-vous une faveur et utilisez le pointeur intelligent approprié. – stefaanv

+0

Ce n'est certainement pas PIMPL. Il n'y a pas de mise en œuvre dans Bar. –

Questions connexes