C++ Errors: " 'class' does not name a type" and "invalid use of incomplete type ‘struct ...' "

984 views Asked by At

Here is a very repetitive issue, also here in StackOverflow, but I do not manage to solve my problem even trying the different answers. So, I have some classes:

main.cpp:

#include "foo.h"
#include "bar.h"

...

foo.h:

#include "bar.h"
class foo {
  foo();
  bar& bind(bar &b);
  gru& bind(gru &g);
};

bar.h:

#include "foo.h"
class bar {
  bar();
  foo& bind(foo &f);
  gru& bind(gru &g);
};

Clearly, I have a cyclic dependency. So I get the infamous error 'bar' does not name a type. In this case, I add class bar; to foo declaration and delete the #include. When I do that, I get: invalid use of incomplete type ‘struct bar'.

I tried in some different ways, also adding class foo; to bar, but I always have some kind of error. In this last case I get:

bar.cpp:48:11: error: prototype for ‘foo& bar::bind(bar::foo&)’ does not match any in class ‘bar’
bar.h:55:12: error: candidates are: gru& bar::bind(gru&)
bar.h:54:13: error:                 bar::foo& bar::bind(bar::foo&)

Plus, I never get any complain about gru. Which, as an additional information, was already there in this program, working perfectly along with bar and main, before I added foo.

Any helpful ideas? Thanks a lot :)

4

There are 4 answers

0
makeMonday On BEST ANSWER

Thank you a lot guys for the answers. In many ways they were helpful.

In the end I realized that I had to reorder all the #include's in my code, because, as you may have realized, there were a lot more coding and what I put here was a simpler version (sorry for that).

So, my final solution was to include class bar; in foo.h and class foo; in bar.h. Then reorder the includes in main.cpp and the Makefile.

Thanks again ;-)

0
Dale Wilson On

in foo.h

  #pragma once //(or use a guard symbol)
  class bar;
  class foo
  {
     bar & bind(bar & b);
  };

in bar.h

  #pragma once //(or use a guard symbol)
  class foo;
  class bar
  {
     foo & bind(foo & f);
  };

in foo.cpp

#include <foo.h>
#include <bar.h>

bar foo:bind(bar & b)
{
  // here you can use bar methods
}

in bar.cpp

#include <bar.h>
#include <foo.h>

foo bar:bind(foo & f)
{
  // here you can use foo methods
}
0
A B On

This will compile fine for me (NOTE: This is without instantiating either the foo or bar class):

FILE bar.h CONTAINS:

#ifndef BAR_H
#define BAR_H

#include "foo.h"

class foo;
class gru;

class bar {

  bar();
  foo& bind(foo &f);
  gru& bind(gru &g);
};

#endif

FILE foo.h CONTAINS:

#ifndef FOO_H
#define FOO_H
#include "bar.h"
class bar;
class gru;
class foo {
  foo();
  bar& bind(bar &b);
  gru& bind(gru &g);
};

#endif

MAIN .cpp FILE CONTAINS:

#include "foo.h"
#include "bar.h"
0
Baltasarq On

The C++ compiler is very old, and furthermore, the part that handles this example in your code is not the compiler itself, but a part of the compiler chain known as the preprocessor. If we can agree on the C++ compiler being not very smart, the preprocessor is a dull, but friendly, assistant.

A *.cpp file is is compiled and later linked with the other *.cpp files in your program. The .h files actually do not have any meaning by themselves: this separation is supposedly an advantage for programmers. The key point here is that, no matter how many *.h files you included in your *.cpp file, finally there will be just a huge, generated cpp file contaning the whole code present in your *.h files, and also the source code present in your *.cpp file itself.

A cyclic dependency could be solved by many ways, but, as you can imagine, the compiler does not even have the opportunity to handle anything before the problem is produced. Cyclic dependencies are not supported in C or C++.

More modern compilers, such as Java or C#, are able to extract the public interface of classes, and use this information when the A class is needed for the B class, and viceversa. Again, this is not possible in C++.

The only solution would be to rewrite your code. The objective is to eliminate the cyclic #include directives. Actually, if your code is as simple as you are showing here, you can easily solve it by using a forward declaration:

// foo.h
class bar;

class foo {
  foo();
  bar& bind(bar &b);
  gru& bind(gru &g);
};

--

// bar.h
class foo;

class bar {
  bar();
  foo& bind(foo &f);
  gru& bind(gru &g);
};

--

// main.cpp
#include "foo.h"
#include "bar.h"

// ...
int main()
{
    // ...
}

A forward declaration makes it possible to let the compiler know that this class actually is going to exist, and you are declaring its presence ahead, but not giving details about its contents. That's why you can just use this forward declaration for a pointer (or reference), inside another class (the compiler would need the size of the forwarded class in order to be able to create an attribute, and that's impossible without details).

There are other concepts to work here, such as compiler guards, for example.

Hope this helps.