2015-05-05 3 views
7

Also ich ein Projekt erstellen, das Vektoren ineinander verschachtelt enthält, aber die Struktur wird nicht kompiliert. Ich denke, dies ist ein Fall von zirkulärer Abhängigkeit, aber alle Fixes, die ich gesehen habe, scheinen nur für Code zu gelten, der Header-Dateien und separate Übersetzungseinheiten enthält.Wie löst man eine zirkuläre Klassenabhängigkeit mit einer gemeinsamen Basisklasse ohne Header?

#include <iostream> 
#include <vector> 

class A { 
public: 
    virtual ~A(); 
}; 

// The following forward declaration statements didn't solve the 
// compiler error: 
// class C; 
// class C : public A; 

class B : public A { 
    std::vector<A*> Avector;  
public: 
    void addC(C* Cin){Avector.push_back(Cin);} 
    ~B(); 
}; 

class C : public A { 
    std::vector<A*> Avector;   
public: 
    void addB(B* Bin){Avector.push_back(Bin);} 
    ~C(); 
}; 

int main() { 
    B b; 
    C c; 
    b.addC(&c); 
    c.addB(&b); 
} 

Ich habe versucht, nach vorn zu erklären mit

class C; 
Class C : public A; 

Aber nichts davon scheint zu funktionieren.

Der Fehler, den ich bekommen ist:

\test\test\source.cpp(15): error C2061: syntax error : identifier 'C' 
\test\test\source.cpp(15): error C2065: 'Cin' : undeclared identifier 

Ist diese Art von Code implementierbar?

Antwort

7

"... aber alle Fixes, die ich gesehen habe, scheinen nur für Code zu gelten, der Header-Dateien und separate Übersetzungseinheiten enthält."

Ich bin damit einverstanden, dass auch ein beliebtes Q & A wie Resolve circular dependencies in c++ nicht wirklich Ihre Frage nicht beantworten, wie diese in einer Datei (Header oder nicht) einzelnen Implementierung zu behandeln.

Aber IMHO gilt es als die bessere Praxis (und wie Sie von these pointers abholen können), Klassendeklarationen in Kopfzeilen und Implementierung/Definition in ihre eigenen Übersetzungseinheiten zu trennen.
Auch bei reinen Header-Bibliotheken (z. B. Vorlagenklassen) sollten Sie eine separate Klassendeklaration (ohne Inline-Code) bereitstellen und die Implementierung in einer separaten Quelldatei bereitstellen, die dort enthalten ist.

Ihr Problem ist hier eigentlich:

class B : public A { 
    // ... 
    void addC(C* Cin) { Avector.push_back(Cin); } 
        // ^^^^^^^^^^^^^^^^^^^^^^^^^^^ 
    // ... 
}; 

An dieser Stelle (auch mit einer Forward-Deklaration von class C;) der Compiler nicht weiß, wie C*-A* zu konvertieren, da die Informationen über die Vererbungsbeziehung sind fehlt (und nein, Sie können keine Vorwärtsdeklarationen wie class C : public A; machen).

"Ist diese Art von Code implementierbar?"

Sie können in einer einzigen Übersetzungseinheit/Header-Datei alles, was tun:

Statt die Funktionsdefinition von inlining mit B ‚s Klassendeklaration, sollten Sie es trennen, nachdem das zu sehen Volldeklaration class C:

class C; 

class B : public A { 
    // ... 
    void addC(C* Cin); 
}; 

class C : public A { 
    // ... 
}; 

inline void B::addC(C* Cin) { Avector.push_back(Cin); } 

class C die volle Erklärung class B sowieso (wegen der Reihenfolge der Deklaration) sehen. So ist es OK, um die Umsetzung

void addB(B* Bin) { Avector.push_back(Bin); } 

aus der class C Erklärung zu verwenden.

+1

Keine Notwendigkeit, die Definition in eine andere Kompilierungseinheit zu legen. Definition von 'B :: AddC' sollte nach' C' Definition sein. – Jarod42

+0

@ Jarod42 Muss es dann inline markiert werden? –

+0

Es scheint, dass der gesamte Code von OP in einer einzigen Übersetzungseinheit ist, also nein, es ist nicht erforderlich. Wenn der Code in der Header-Datei war, ja. – Jarod42

1

Ich hatte versucht zu deklarieren, und ich hatte versucht, die Funktion Implementierung nach dem zweiten Teil, aber ich hatte nicht beide gleichzeitig versucht. Der feste Code für alle diese 10 Jahre googeln später:

#include<iostream> 
    #include<vector> 

    using namespace std; 

    class C; 

    class A 
    { 
    public: 
     virtual ~A(); 
    }; 

    class B : public A 
    { 
    public: 
     vector<A*> Avector; 

     void addC(C* Cin); 
     ~B(); 
    }; 

    class C : public A 
    { 
    public: 
     vector<A*> Avector; 

     void addB(B* Bin) 
     { 
      Avector.push_back(Bin); 

     }; 
      ~C(); 
     }; 

    void B::addC(C* Cin) 
    { 
     Avector.push_back(Cin); 
    } 

    int main() 
    { 

    } 

Mein Dank geht an πάντα ῥεῖ und ein Gruß an Jarod42.

+1

Sie müssen keine Antwort erneut posten. Dass du meine akzeptiert hast, gibt bereits an, dass du das Problem dafür gelöst hast (ich habe auch ein paar kleine Verbesserungen hinzugefügt). –