Incomplet "type" dans la classe qui a un membre du même type de la classe elle-même

j'ai une classe qui doit avoir un membre privé de la même classe, quelque chose comme:

class A {
    private:
        A member;
}

mais il me dit que membre est un type incomplet. Pourquoi? Il ne me dit pas incomplet type si j'utilise un pointeur, mais je préfère ne pas utiliser un pointeur. Toute aide est appréciée

33
demandé sur nbro 2011-06-15 00:39:37

8 réponses

Au moment où vous déclarez votre membre, vous êtes toujours définirA de la classe, de sorte que le type A n'est pas encore défini.

Toutefois, lorsque vous écrivez A*, le compilateur sait déjà que A signifie un nom de classe, et donc le type "pointer vers A" est défini. C'est pourquoi vous pouvez incorporer un pointeur vers le type de votre définition.

la même logique s'applique aussi aux autres types, donc si vous écrire:

class Foo;

vous déclarez la classe Foo, mais vous ne la définissez jamais. Vous pouvez écrire:

Foo* foo;

Mais non:

Foo foo;

d'un autre côté, quelle structure de mémoire attendez-vous pour votre type A si le compilateur permettait une définition récursive ?

cependant, il est parfois logique d'avoir un type qui se réfère d'une façon ou d'une autre à une autre instance du même type. Les gens utilisent généralement des pointeurs pour cela ou même mieux: pointeurs intelligents (comme boost::shared_ptr) pour éviter d'avoir à traiter avec la suppression manuelle.

quelque Chose comme:

class A
{
  private:
    boost::shared_ptr<A> member;
};
37
répondu ereOn 2011-06-14 20:49:22

voici un exemple concret de ce que vous tentez d'accomplir:

class A {
public:
    A() : a(new A()) {}
    ~A() { delete a; a = nullptr; }
private:
    A* a;
};

A a;

Heureux De Débordement De Pile!

23
répondu Nick 2015-01-23 07:48:51

A est "incomplet" jusqu'à la fin de sa définition (bien que cela n'inclut pas les corps de fonctions des membres).

une des raisons en est que, tant que la définition n'est pas terminée, il n'y a aucun moyen de savoir à quel point A (qui dépend de la somme des tailles des membres, ainsi que quelques autres choses). Votre code en est un bon exemple: votre type A est défini par la taille du type A.

Clairement, un objet de type A ne peut pas contenir d' objet membre qui est aussi de type A.

Vous aurez pour stocker un pointeur ou une référence, vouloir stocker est peut-être suspect.

5
répondu Lightness Races in Orbit 2011-06-14 20:47:30

vous ne pouvez pas inclure a dans A. Si vous avez pu le faire, et que vous avez déclaré, par exemple, A a;, vous devez vous référer à a.member.member.member... infini. Vous n'avez pas autant de RAM disponible.

2
répondu mah 2011-06-14 20:42:51

Comment une instance de class A contient aussi une autre instance de class A?

il peut tenir un pointeur vers A Si vous voulez.

1
répondu Andrei 2011-06-14 20:44:05

Ce type d'erreur se produit lorsque vous essayez d'utiliser une classe qui n'a pas encore totalement DÉFINI.

Essayez d'utiliser A* member à la place.

1
répondu trema 2011-06-14 21:11:34

le problème se produit lorsque le compilateur rencontre un objet d'un code in. Le compilateur frottera sa main et partira faire un objet de A. Tout en faisant cela il verra que A a un membre qui est de nouveau de type A. Ainsi pour compléter l'instanciation de A il doit maintenant instancier un autre A ,et en faisant cela il doit instancier un autre a et ainsi de suite. Vous pouvez voir qu'il finira dans une récursion sans limite. Ce n'est donc pas autorisé. Compilateur s'assure qu'il connaît tous les types et la mémoire exigence de tous les membres avant qu'il ne commence l'instanciation d'un objet d'une classe.

0
répondu Sushovan 2015-02-10 10:28:17

une façon simple de comprendre la raison derrière la classe A incomplet est d'essayer de regarder du point de vue du compilateur.

entre autres choses, le compilateur doit pouvoir calculer la taille de A objet. Connaître la taille est une exigence très basique qui apparaît dans de nombreux contextes, comme allouer de l'espace en mémoire automatique, appeler l'opérateur new, et l'évaluation de sizeof(A). Cependant, en calculant la taille deA nécessite de connaître la taille de A, parce que a est un membre de A. Cela conduit à une récursion infinie.

la façon dont le compilateur traite ce problème est de considérer A incomplète jusqu'à ce que sa définition est parfaitement connu. Vous êtes autorisé à déclarer des pointeurs et des références à la classe incomplète, mais vous n'êtes pas autorisé à déclarer les valeurs.

0
répondu dasblinkenlight 2016-08-31 14:00:12