web-dev-qa-db-fra.com

Problème de déclaration de classe/transmission imbriquée C++

Est-il possible de déclarer une classe imbriquée, puis de l'utiliser comme type pour un membre de données concret (ne pointant pas vers/référant à) de la classe externe?

C'EST À DIRE.

class Outer;

class Outer::MaybeThisWay   // Error: Outer is undefined
{
};

class Outer
{
 MaybeThisWay x;

 class MaybeThatOtherWay;

 MaybeThatOtherWay y;   // Error: MaybeThatOtherWay is undefined
};
32
uj2

Vous ne pouvez pas transmettre-déclarer une classe imbriquée comme ça.

Selon ce que vous essayez de faire, vous pouvez peut-être utiliser un espace de noms plutôt qu'une classe sur la couche externe. Vous pouvez transmettre-déclarer une telle classe sans problème:

namespace Outer {
   struct Inner; 
};

Outer::Inner* sweets;  // Outer::Inner is incomplete so 
                       // I can only make a pointer to it

Si votre Outer doit absolument être une classe et que vous ne pouvez pas le transformer en un espace de noms, il vous faudra alors qu'Outer soit un type complet dans le contexte où vous déclarez Inner. 

class Outer
{
   class Inner;  // Inner forward-declared
};  // Outer is fully-defined now

Outer yes;  // Outer is complete, you can make instances of it
Outer::Inner* fun;  // Inner is incomplete, you can only make 
                    // pointers/references to it

class Outer::Inner 
{
};  // now Inner is fully-defined too

Outer::Inner win;  // Now I can make instances of Inner too
37
janks

Il n'y a aucun moyen d'avancer pour déclarer une classe imbriquée sans spécifier complètement la classe contenue. Ce petit truc résout un peu le problème

class Outer_Inner
{
};

class Outer
{
public:
   typedef Outer_Inner Inner;
};

Cela fonctionne pour moi car dans ma convention d'appellation Outer_Inner n'est pas un nom de classe valide, il est donc évident qu'il se réfère à une classe imbriquée.

Vous ne pouvez toujours pas transférer la classe imbriquée comme ceci:

class Outer::Inner;

Mais au moins, il peut être déclaré avec:

class Outer_Inner;

Si vous n'aimez pas l'apparence de Outer_Inner, vous pouvez adopter une convention de dénomination pour les classes imbriquées qui convient le mieux à vos goûts. Outer__Inner, Outer_nested_Inner, etc.

15
deft_code

Non, mais quel est le problème avec

class Outer {
public:  //or protected or private
    class Inner {
    };

private:
    Inner foo;
};

Déclarer en aval n'a pas de sens ici, à moins que je manque quelque chose (ce qui est possible étant donné que votre question manque de détails)

N'oubliez pas que si une classe est déclarée en aval, vous ne pouvez déclarer que des références ou des pointeurs vers un objet du type déclaré en aval Vous ne pouvez rien faire d'autre, y compris accéder à ses membres ou à ses fonctions.

1
Glen

Si une classe a été déclarée en aval (mais vous n'avez pas encore la définition complète), vous ne pouvez alors déclarer qu'un pointeur sur elle, car le compilateur ne connaît pas encore la taille de la classe ou méthodes).

1
Ken Bloom

Si vous déclarez un attribut de type MaybeThatOtherWay, et non une référence ou un pointeur, le compilateur doit connaître la définition complète de la classe pour déterminer la taille de la classe externe. Ainsi, vous ne pouvez pas utiliser la déclaration anticipée et ce type de déclaration de champ, que ce soit une classe imbriquée ou non.

0
Seb

Si vous avez simplement besoin d'un type en tant que paramètre de fonction ou variable statique, vous pouvez le faire côté client. Par exemple, pour recevoir une notification d'événement de l'extérieur:

Interface:

class Client {
public:
private:
    static void gotIt(int event);
    class Helper;
};

La mise en oeuvre:

#include <outer.hpp>

class Client::Helper {
public:
    static void fromOuter(Outer::Inner const& inner) 
    { 
        gotIt(inner.event());
    }
};
0
zzz777