wake-up-neo.net

"Unvollständiger Typ" in der Klasse, die einen Member des gleichen Typs der Klasse selbst hat

Ich habe eine Klasse, die ein privates Mitglied derselben Klasse haben sollte, etwa:

class A {
    private:
        A member;
}

Aber es sagt mir, dass das Mitglied ein unvollständiger Typ ist. Warum? Wenn ich einen Zeiger verwende, wird mir nicht der unvollständige Typ mitgeteilt, aber ich würde lieber keinen Zeiger verwenden. Jede Hilfe wird geschätzt

34
Sterling

Wenn Sie Ihr Mitglied deklarieren, sind Sie noch definierend die A-Klasse, daher ist der Typ A noch undefiniert.

Wenn Sie A* schreiben, weiß der Compiler jedoch bereits, dass A für einen Klassennamen steht, und der Typ "Zeiger auf A" ist definiert. Deshalb können Sie einen Zeiger auf den Typ einbetten, den Sie definieren.

Die gleiche Logik gilt auch für andere Typen. Wenn Sie also nur schreiben:

class Foo;

Sie erklären die Klasse Foo, definieren sie aber nie. Du kannst schreiben:

Foo* foo;

Aber nicht:

Foo foo;

Andererseits, welche Speicherstruktur würden Sie für Ihren Typ A erwarten, wenn der Compiler eine rekursive Definition zulässt?

Es ist jedoch manchmal logisch gültig, einen Typ zu haben, der sich irgendwie auf eine andere Instanz desselben Typs bezieht. Normalerweise verwenden die Leute Zeiger dafür oder noch besser: intelligente Zeiger (wie boost::shared_ptr), um das manuelle Löschen zu vermeiden.

So etwas wie:

class A
{
  private:
    boost::shared_ptr<A> member;
};
38
ereOn

Dies ist ein funktionierendes Beispiel für das, was Sie erreichen wollen:

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

A a;

Happy Stack-Überlauf!

25
Nick

A ist bis zum Ende ihrer Definition "unvollständig" (dies schließt jedoch nicht die Körper der Mitgliedsfunktionen ein).

Einer der Gründe dafür ist, dass es bis zum Ende der Definition nicht möglich ist, zu wissen, wie groß A ist (was von der Summe der Größen der Mitglieder und einigen anderen Faktoren abhängt). Ihr Code ist ein hervorragendes Beispiel dafür: Ihr Typ A wird durch die Größe des Typs A definiert.

Natürlich darf ein Objekt vom Typ A kein Member-Objekt enthalten, das ebenfalls vom Typ A ist.

Sie müssen einen Zeiger oder eine Referenz speichern. zu speichern, ist möglicherweise verdächtig.

Sie können A nicht in A einschließen. Wenn Sie dies tun könnten und beispielsweise A a; deklariert haben, müssen Sie unendlich oft auf a.member.member.member... verweisen. Sie haben nicht so viel RAM zur Verfügung.

2
mah

Wie kann eine Instanz von class A auch eine andere Instanz von class A enthalten?

Es kann einen Zeiger auf A halten, wenn Sie möchten.

1
Andrei

Diese Art von Fehler tritt auf, wenn Sie versuchen, eine Klasse zu verwenden, die noch nicht vollständig DEFINED ist.

Verwenden Sie stattdessen A* member.

1
trema

Eine einfache Möglichkeit, den Grund für die Unvollständigkeit der Klasse A zu verstehen, besteht darin, sie aus der Perspektive des Compilers zu betrachten.

Der Compiler muss unter anderem die Größe des A-Objekts berechnen können. Die Größe zu kennen, ist eine sehr grundlegende Anforderung, die sich in vielen Zusammenhängen zeigt, z. B. bei der Zuordnung von Speicherplatz im automatischen Speicher, dem Aufruf des Operators new und der Auswertung von sizeof(A). Um die Größe von A zu berechnen, müssen Sie jedoch die Größe von A kennen, da a ein Mitglied von A ist. Dies führt zu einer unendlichen Rekursion.

Der Umgang des Compilers mit diesem Problem besteht darin, A als unvollständig zu betrachten, bis seine Definition vollständig bekannt ist. Sie dürfen Zeiger und Verweise auf unvollständige Klassen deklarieren, Werte dürfen jedoch nicht deklariert werden.

0
dasblinkenlight

Das Problem tritt auf, wenn der Compiler im Code auf ein Objekt von A stößt .. Der Compiler reibt sich die Hand und legt fest, dass er ein Objekt von A machen soll. Dabei wird festgestellt, dass A ein Member hat, das wiederum vom Typ A ist Um die Instantiierung von A zu vollenden, muss es nun ein anderes A initialisieren, und dabei ein anderes A und so weiter. Sie können sehen, dass es in einer Rekursion ohne Begrenzung endet. Daher ist dies nicht erlaubt. Der Compiler stellt sicher, dass er alle Typen und Speicheranforderungen aller Member kennt, bevor er ein Objekt einer Klasse instanziiert. 

0
Sushovan