Frage

Ich habe ein Problem, das ich denke, ist diesbezügliche Erklärungen zu übermitteln, aber vielleicht auch nicht.

Hier ist der relevante Code:

A. h

#ifndef A_H_
#define A_H_

#include "B.h"

class A
{
    private:
        B b;

    public:
        A() : b(*this) {}

        void bar() {}
};

#endif /*A_H_*/

B.h

#ifndef B_H_
#define B_H_

#include "A.h"

class A;

class B
{
    private:
        A& a;

    public:
        B(A& a) : a(a) {}

        void foo() { /*a.bar();*/ } //doesn't compile
};

#endif /*B_H_*/

main.cpp

#include "A.h"

int main()
{
    A a;

    return 0;
}

Das Problem scheint mit dem Aufruf von A :: bar zu sein (). Das Programm erfolgreich kompiliert, bis ich diese Methode aufzurufen versuchen, an welcher Stelle ich zwei Fehler bekommen:

  

Fehler: ungültige Verwendung von unvollständigem Typ ‚struct A‘

     

Fehler: Forward-Deklaration von ‚struct A‘

Ich nehme an, dies liegt daran, dass A :: bar () hat noch da beide Header aufeinander verweisen definiert oder erklärt werden. Ich jedoch vorwärts Klasse A erklärt und bin ratlos, was ich sonst noch tun müssen. Ich bin neu in C ++, so bitte vergib mir. Ich konnte nicht die Antwort auf diese Frage anderswo online finden. Wie immer Vielen Dank im Voraus!

War es hilfreich?

Lösung

Sie haben einen zirkulären Verweis bekommen, so müssen Sie B. H. trennen Versuchen Sie so etwas wie:

B.h:

#ifndef B_H_
#define B_H_

// don't include A.h here!

class A;

class B
{
   private:
      A& a;

   public:
      B(A& a) : a(a) {}

      void foo();
};

#endif /*B_H_*/

B.cpp:

#include "B.h"
#include "A.h"

void B::foo() { a.bar(); } // now you're ok

Edit: Erklärung dafür, warum müssen Sie es in zwei Dateien aufgeteilt:

Die Klasse B enthält einen Verweis auf A, die eine so genannte sein kann unvollständig Typ. Sie können keine Funktionen nennen, da der Compiler noch nicht weiß, was zum Teufel A ist - er weiß nur, dass es sich um eine Klasse von einer Art ist. Sobald Sie A. h (in der CPP-Datei) enthalten, dann ist A eine komplette Art, und man kann mit ihr, was Sie tun.

Sie können nicht die ganze Sache in einer Header-Datei halten, weil Sie einen zirkulären Verweis bekommen. Sie verhindert eine Endlosschleife mit Wachen sind, aber Sie bekommen etwas, was Sie nicht wollen. Schauen Sie, was der Compiler endet mit, wenn Sie kompilieren main.cpp, wie Sie es hatte vor:

// #include "A.h" ==>
#define A_H_

// #include "B.h" ==>
#define B_H_

// #include "A.h" ==> nothing happens! (since A_H_ is already defined)

class A;

class B {
private:
    A& a;

public:
    B(A& a) : a(a) {}

    void foo() { a.bar(); } // <-- what the heck is A here?
                            //     it's not defined until below
};

class A {
private:
   B b;

public:
   A() : b(*this) {}

   void bar() {}
};

int main() {
    A a;
    return 0;
}

Andere Tipps

Die Linie #include<file.h> wird nur die Zeile mit dem Inhalt von file.h ersetzen. Also, wenn der Computer Ihre main.cpp zu kompilieren versucht, wird es alles zusammen ziehen, die wie folgt aussieht. An der Stelle, Sie A :: bar verwenden möchten () wurde nicht definiert.

// result from #include "A.h"

#ifndef A_H_
#define A_H_

// Now, #include "B.h" in A.h will get you the following
#ifndef B_H_
#define B_H_

// here you include "A.h" again, but now it has no effect
// since A_H_ is already defined

class A;

class B
{
    private:
            A& a;
    public:
            B(A& a) : a(a) {}
            // Oops, you want to use a.bar() but it is not defined yet
            void foo() { /*a.bar();*/ } 
};

#endif /*B_H_*/

class A
{
    private:
            B b;
    public:
            A() : b(*this) {}
            void bar() {}
};
#endif /*A_H_*/

// now this is your main function
int main()
{
    A a;
    return 0;
}

Wie mehrere andere erwähnt haben, wird die kreisförmige Referenz Ihr Problem sein. Ein anderer Ausdruck dafür wäre „gegenseitige Abhängigkeit“ sein. Doch anstatt zu versuchen, die richtige Syntax zu finden Ihre Anwendung zu kompilieren und laufen (ich das eigentliche Problem annehmen, besteht in einem Programm etwas weiter fortgeschritten als das, was Sie gebucht haben), würde ich empfehlen Ihnen, das Problem von einer objekt- angreifen orientiertes Design Standpunkt.

Als allgemeine Regel sollten die gegenseitigen Abhängigkeiten, wo immer möglich vermieden werden. Ich habe zuvor in meinem eigenen Code über dieses Problem kommen (was in einigen Tagen des Debugging führte, zerreißt mir die Haare aus, und flucht meinen Compiler), und hier ist, wie ich war schließlich in der Lage, sie zu überwinden. Ich werde eine verwässerte Version von meinem eigenen Problem als ein konkretes Beispiel vorstellen, wie das Problem zu beheben, so dass hoffentlich können Sie den verborgenen Sinn dahinter, extrahieren und es wird alles Sinn macht, am Ende.

Nehmen wir an, wir haben zwei Klassen: Die Daten und Dataanalyzer

Daten enthalten einen Verweis auf Dataanalyzer (verwendet, um die Daten zu analysieren) und Dataanalyzer enthält einen Verweis auf Daten (die Daten analysiert werden) - gegenseitige Abhängigkeit! Um diese Abhängigkeit zu beseitigen, extrahieren wir eine Schnittstelle aus (in C ++, eine rein virtuelle Klasse) von Dataanalyzer, dass die öffentlichen Methoden / Attribute erforderlich auf Dataanalyzer definiert. Es könnte etwa so aussehen:

class IAnalyzer
{
public:
    virtual void Analyze () = 0;
};

Wenn wir definieren Dataanalyzer, wir tun es wie folgt:

class DataAnalyzer : public IAnalyzer
{
public:
    DataAnalyzer (Data* data);

    virtual void Analyze (); // defined in DataAnalyzer.cpp
};

Und Daten wie folgt aussehen:

class Data
{
public:
    Data ();

    IAnalyzer* Analyzer;
};

Irgendwo in Ihrer Controller-Klasse, man könnte so etwas wie hat:

void main ()
{
    Data*  data = new Data ();
    data->Analyzer = new DataAnalyzer (data);
}

Nun Daten steht für sich allein (soweit sie weiß, hat IAnalyzer keinen Verweis auf Daten benötigen), und nur Dataanalyzer ist abhängig von Daten. Wenn Sie gehen halten möchten, können Sie auch weiterhin Dataanalyzer die Abhängigkeit von Daten, sondern im Interesse der einfach brechen die gegenseitige Abhängigkeit zu entfernen, sollte dies ausreichend sein.

. Achtung: Ich habe diesen Code nicht getestet kompilieren, so dass es einige geringfügige Anpassung erfordert ordnungsgemäß zu kompilieren und auszuführen

Viel Glück!

Wenn Sie wirklich wollen B :: foo Sie sein Inline könnte die Umsetzung in B.h tun, obwohl ich es nicht empfehlen würde.

B.h:

#ifndef B_H_
#define B_H_

// Forward declaration of A.
class A;

class B
{
private:
    A& a;

public:
    B(A& a) : a(a) {}

    void foo();
};

// Include definition of A after definition of B.
#include "A.h"

inline void B::foo()
{
    a.bar();
}

#endif /*B_H_*/

A. h:

// Include definition of B before definition of A.
// This must be done before the ifndef A_H_ include sentry,
// otherwise A.h cannot be included without including A.h first.
#include "B.h"

#ifndef A_H_
#define A_H_

class A
{
private:
    B b;

public:
    A() : b(*this) {}

    void bar() {}
};

#endif /*A_H_*/

In B.h, Sie sind einschließlich A. h sowie nach vorn A erklärt.

Sie müssen B.h in B.h und B.cpp, trennen oder die Vorwärtsdeklaration entfernen.

PS: Sie haben auch eine zirkuläre Abhängigkeit. A. h wird einschließlich B.h, und vice versa. Ihre Wachen fangen das Problem, obwohl;)

auf die anderen Antwort (circular Referenz, die die richtige Antwort) hinzuzufügen, wenn Sie von C # / Java kommen, verstehen, dass C ++ anders ist, dass Dateien, um analysiert werden (statt als Ganze betrachtet ). Sie muß also vorsichtig sein, um sicherzustellen, dass alles definiert wird, bevor es verwendet wird, in der tatsächlichen Reihenfolge der Dateien enthalten sind (und / oder getrennte Funktionen in CPP-Dateien je nach Bedarf).

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top