0

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?

1 Answers1

1

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.

T.C.
  • 133,968
  • 17
  • 288
  • 421
Gary Kaizer
  • 274
  • 1
  • 7
  • This worked, thank you. I wonder how one would deal with this issue if one of the classes used the other as a value, rather than a reference type – Wuschelbeutel Kartoffelhuhn Mar 19 '15 at 01:04
  • As long as you deal with pointer you execute your code in the .cpp file instead of inlining your function in the .hpp and in the .cpp you #include "Foo.hpp" or "Bar.hpp", thus the headers only know it's a pointer, but the .cpp file will know the offsets & type information ! See my edit ! – Gary Kaizer Mar 19 '15 at 01:08
  • Also just a heads up ! instead of using #ifndef BAR_HPP_ #define BAR_HPP_ #endif You can instead just put: #pragma once – Gary Kaizer Mar 19 '15 at 01:13
  • Are you implying that if confronted with a circular class dependency, one MUST use reference types (and forward class declarations), but this is not a problem since the implementations can dereference them? I also don't understand why the implementation files know the offsets, but the header files don't - maybe because .cpp's only become relevant at runtime, after compilation, but all the header files must know stuff at compile time. Thanks for your clarifications. – Wuschelbeutel Kartoffelhuhn Mar 19 '15 at 01:19
  • The header file DOESN'T need to know the implementation. The actual usage of the functions should know the implementation, but since you don't include .cpp file you can't get direct circular reference. You should almost NEVER do "#include "file.cpp". The header file just needs to know it's a pointer, the actual **usage** of the pointer needs to know the offsets ! – Gary Kaizer Mar 19 '15 at 01:22
  • What on earth is "link time prototype resolution"?! And `Bar::collide()` can be declared to take a `Foo` by value just fine. The test is that a class definition is required when a complete type is required. And a member function declaration without a definition doesn't require a complete type. – T.C. Mar 19 '15 at 05:32
  • Im trying not to get too wordy with my answer, without going into details about how objects are linked and when it matters to know the complete type information. All the compiler needs to know is thay Foo& or Bar* are pointers for the header files and that they are of types called Foo and Bar, the linker needs to check the function signatures and link them with the function implemenations which need to know complete type information. But considering the audience for this question that might be a little too verbose. – Gary Kaizer Mar 19 '15 at 05:42