Alles korrekt. Trotzdem seltsame Fehler.



  • Hallo!

    Ich habe hier das folgende kleine simple Beispielprogramm:

    // A.cpp
    #include "A.hpp"
    
    void A::foo()
    {
      b = new B();
      b->bar();
    }
    
    void A::bar()
    {
    }
    
    // A.hpp
    #ifndef __A_HPP__
    #define __A_HPP__
    
    #include "B.cpp"
    
    class A
    {
    public:
      B *b
      void foo();
      void bar();
    };
    
    #endif
    
    // B.cpp
    #include "B.hpp"
    
    void B::foo()
    {
      a = new A();
      a->bar();
    }
    
    void B::bar()
    {
    }
    
    // B.hpp
    #ifndef __B_HPP__
    #define __B_HPP__
    
    #include "A.hpp"
    
    class B
    {
    public:
      A *a;
      void foo();
      void bar();
    };
    
    #endif
    
    // main.cpp
    #include "A.hpp"
    #include "B.hpp"
    
    main()
    {
      A a;
      a.foo();
      B b;
      b.foo();
    }
    

    Wenn ich das mit

    g++ main.cpp A.cpp B.cpp
    

    kompileire bekomme ich die folgenden seltsamen Fehlermeldungen:

    In file included from B.cpp:2,
                     from A.hpp:5,
                     from main.cpp:2:
    B.hpp:10: error: ISO C++ forbids declaration of `A' with no type
    B.hpp:10: error: expected `;' before '*' token
    In file included from A.hpp:5,
                     from main.cpp:2:
    B.cpp: In member function `void B::foo()':
    B.cpp:6: error: `a' was not declared in this scope
    B.cpp:6: error: `A' has not been declared
    In file included from main.cpp:2:
    A.hpp: At global scope:
    A.hpp:11: error: expected `;' before "void"
    main.cpp: In function `int main()':
    main.cpp:8: error: 'class A' has no member named 'foo'
    In file included from B.cpp:2,
                     from A.hpp:5,
                     from A.cpp:2:
    B.hpp:10: error: ISO C++ forbids declaration of `A' with no type
    B.hpp:10: error: expected `;' before '*' token
    In file included from A.hpp:5,
                     from A.cpp:2:
    B.cpp: In member function `void B::foo()':
    B.cpp:6: error: `a' was not declared in this scope
    B.cpp:6: error: `A' has not been declared
    In file included from A.cpp:2:
    A.hpp: At global scope:
    A.hpp:11: error: expected `;' before "void"
    A.cpp:5: error: no `void A::foo()' member function declared in class `A'
    A.cpp: In member function `void A::foo()':
    A.cpp:6: error: `b' was not declared in this scope
    A.cpp: At global scope:
    A.cpp:11: error: no `void A::bar()' member function declared in class `A'
    A.cpp:11: error: `void A::bar()' and `void A::bar()' cannot be overloaded
    In file included from A.hpp:5,
                     from B.hpp:5,
                     from B.cpp:2:
    B.cpp:4: error: `B' has not been declared
    B.cpp: In function `void foo()':
    B.cpp:6: error: `a' was not declared in this scope
    B.cpp:6: error: `A' has not been declared
    B.cpp: At global scope:
    B.cpp:10: error: `B' has not been declared
    In file included from B.hpp:5,
                     from B.cpp:2:
    A.hpp:10: error: ISO C++ forbids declaration of `B' with no type
    A.hpp:10: error: expected `;' before '*' token
    

    Warum? Und was kann ich dagegen tun?



  • Wieso "alles korrekt"? Das ist sehr anmaßend gegenüber des Compilers, der weiß es in den allermeisten Fällen (so auch hier) besser.

    1. __ Präfixe sind dem Compiler vorbehalten, also:

    // A.hpp
    #ifndef A_HPP
    #define A_HPP
    

    2. man inkludiert im allgemeinen keine Implementationsdatei, ist hier auch nicht sinnvoll

    // #include "B.cpp"
    #include "B.hpp"
    

    3. Der Präprozessor ist dumm. Das ist eine allgemeingültige Aussage, so ähnlich wie "Die Wirtschaft ist böse." Egal wie du es drehst, diese Zeile bringt dir nichts. B.hpp wird von A.hpp inkludiert (siehe main.cpp) bevor die Klasse A deklariert wurde. Das include hier verläuft schon in der ersten Zeile von A.hpp, da A_HPP bereits beim ersten inkludieren von A.hpp definiert wurde.
    Der einzige Ausweg (der hier auch ohne Probleme möglich ist, da a nur ein Zeiger auf A ist ist folgendes:

    // #include "A.hpp"
    class A;
    

    Nun muss allerdings B.cpp zusätzlich zu B.hpp noch A.hpp inkludieren, aber das sollte man generell tun.

    4. main hat keine impliziten int-Rückgabetyp, dieser muss angegeben werden

    // main()
    int main ()
    

    4 > 0 => !(alles korrekt) :p



  • zu 1:
    Wusste ich nicht. Danke.

    zu 2:
    Tippfehler. Sowas mache ich normalerweise nicht (Außer bei templates).

    zu 3:
    Danke, das löst das Problem.

    zu 4:
    Hab ich in der Eile vergessen.

    BTW: Was macht man denn bei so einem Problem:

    // A.cpp
    #include "B.hpp"
    #include "A.hpp"
    
    void A::foo()
    {
      B* b = new B();
      b->bar = 42;
    }
    
    // A.hpp
    #ifndef A_HPP
    #define A_HPP
    
    class B;
    
    class A
    {
    private:
      int bar;
    public:
      friend void B::foo();
      void foo();
    };
    
    #endif
    
    // B.cpp
    #include "A.hpp"
    #include "B.hpp"
    
    void B::foo()
    {
      A* a = new A();
      a->bar = 42;
    }
    
    // B.hpp
    #ifndef B_HPP
    #define B_HPP
    
    class A;
    
    class B
    {
    private:
      int bar;
    public:
      friend void A::foo();
      void foo();
    };
    
    #endif
    
    // main.cpp
    #include "A.hpp"
    #include "B.hpp"
    
    int main()
    {
      A *a = new A();
      a->foo();
      B *b = new B();
      b->foo();
    }
    

    Der Compiler meint:

    In file included from main.cpp:2:
    A.hpp:12: error: member `void B::foo()' declared as friend before type `B' defined
    In file included from B.cpp:2:
    A.hpp:12: error: member `void B::foo()' declared as friend before type `B' defined
    B.cpp: In member function `void B::foo()':
    A.hpp:10: error: `int A::bar' is private
    B.cpp:8: error: within this context
    In file included from A.cpp:2:
    B.hpp:12: error: member `void A::foo()' declared as friend before type `A' defined
    A.cpp: In member function `void A::foo()':
    B.hpp:10: error: `int B::bar' is private
    A.cpp:8: error: within this context
    

    Gibt's hier auch so einen Trick, oder muss man sich gleich mit der ganzen Klasse anfreunden?



  • Du hast Spaß mit deinen zyklischen Abhängigkeiten, wa? 😉
    Naja, aber das neue Problem ist an sich nicht lösbar (zumindest sehe ich keine Lösung). B muss die gesamte Deklaration von A kennen, welches die gesamte Deklaration von B kennen muss. Das ist nicht möglich (um das nochmal zu betonen).
    Ein reales Problem dieser Art fußt praktisch immer auf einem miesen Klassendesign, also versuch gar nicht erst, weiter über eine Lösung nachzudenken 😉



  • Das einzige was stört ist die Tatsache, dass "bar" private ist und direkt verändert werden soll.... also mache einfach eine public-Funktion "setBar" in beiden Klassen oder mach "bar" gleich public und schmeiße die friend-Deklarationen raus!

    🙂


Anmelden zum Antworten