Search code examples
c++c++11gccwindows-7eclipse-cdt

Circular class dependencies: Forward declaration error vs. #include error ("template argument invalid")


EDIT: For anyone who finds this question in the future, the following read helped me a lot: http://www.umich.edu/~eecs381/handouts/IncompleteDeclarations.pdf

I have a class whose header file looks approximately like

#ifndef FOO_HPP_
#define FOO_HPP_

#include <memory>
#include "Bar.hpp"
using namespace std;

class Foo {

    shared_ptr<Bar>  bar;
    //other members omitted
};

#endif /* FOO_HPP_ */

I get a compile time error: template 1 is invalid (for the bar member).

Bar.hpp looks approximately like:

#ifndef BAR_HPP_
#define BAR_HPP_

#include "Foo.hpp"
using namespace std;

class Bar {

//private and protected member omitted

public:
//other public members omitted
    virtual int collide(bool p, Foo& f) = 0;
};

#endif /* BAR_HPP_ */

If I now replace the #include "Bar.hpp" in "Foo.hpp" with class Bar;, CDT will underline it with an error: forward declaration of 'class Bar'

How can I resolve this issue?


Solution

  • This issue is because bar.hpp is using foo.hpp and foo.hpp is using bar.hpp

    To Solve this issue write this into foo.hpp and remove bar.hpp reference:

    #ifndef FOO_HPP_
    #define FOO_HPP_
    
    #include <memory>
    using namespace std;
    
    class Bar; //<====== add this
    
    class Foo {
    
        shared_ptr<Bar>  bar;
        //other members omitted
        void DoWork(); //<===== Function that does stuff to bar
    };
    
    #endif /* FOO_HPP_ */
    

    And in Foo.cpp

    #include "Foo.hpp"
    #include "Bar.hpp"
    
    void Foo::DoWork()
    {
         bar.Func();
    }
    

    And in bar.hpp:

    #ifndef BAR_HPP_
    #define BAR_HPP_
    
    using namespace std;
    class Foo; //<====== add this
    class Bar {
    
    //private and protected member omitted
    
    public:
    //other public members omitted
        void Func()
        {
            while(true); //Hang for debug
        };
    
        virtual int collide(bool p, Foo& f) = 0;
    };
    

    As long as you use reference types (Foo* or Foo& instead of Foo directly) this will cause a link time prototype resolution, which should work for you.