0
class a;
class b;

class a {
    b c;
};

class b {
};

Why doesn't this compile? I was under the impression that if you declared prototypes of classes, it didn't matter in which order they were declared. However, this doesn't work. In visual studio, it gives me:

error C2079: 'a::c' uses undefined class 'b'

In g++, it gives me:

error: field 'c' has incomplete type

What am I doing wrong?

BWG
  • 2,238
  • 1
  • 20
  • 32
  • 1
    It **does** matter what order classes are defined in. Definitions must be available before by-value use. – Oliver Charlesworth Dec 26 '13 at 21:01
  • 1
    It would probably work as you expect if `c` was a `b*` (pointer) – Trojan Dec 26 '13 at 21:02
  • Oli, here http://stackoverflow.com/a/6188095/2159051 it says literally "any order will do". And what is the purpose of prototypes then? – BWG Dec 26 '13 at 21:04
  • trojansdestroy okay I tried it, and you are right. Why is that? What if I want an instance of it, not a pointer? – BWG Dec 26 '13 at 21:06
  • In that answer, all classes are prototyped, so the order of definitions doesn't matter. However, those definitions don't show any content. You can't have a member of class that hasn't been defined yet; however, you can have a member that is a pointer to an undefined class. See the next answer on your linked question. – Trojan Dec 26 '13 at 21:07
  • If you want an instance of `b`, you have to *define* (not just declare) `class b` before `class a`. – Trojan Dec 26 '13 at 21:08

2 Answers2

4

When the compiler sees

class a {
  b c;
};

it knows that b exist, but it doesn't know what it is (hence, it doesn't know how much space it will require, hence it doesn't know how to build a)

However what you could do is using a pointer on b:

class a {
  b* c;
};

Edit:

It means you won't be able to manipulate a b before it is defined. E.g: you can't do:

class a {
  b* c;
  void f(){
    c->doSomething(); // <- Won't compile
  }

};

What you can do is separating a definition in a .hh and .cc:

in a.hh

class b; //Say it exists. Don't say what it looks like

class a {
  b* c;
  void f();
};

in a.cc

#include "b.hh" //now it's ok to use b.hh: it won't yield a circular reference because b.hh may include a.hh but it doesn't include a.cc

void a::f(){
  c->doSomething();
}
gturri
  • 13,807
  • 9
  • 40
  • 57
  • Okay this is a good answer. This makes sense. So this means there is no way to have an instance of something before it is defined? – BWG Dec 26 '13 at 21:11
  • You can have an instance if you're called with one, but you won't be able to do much with it... I just edited my answer to provide the solution. – gturri Dec 26 '13 at 21:22
  • Hmm. This does answer my question. Accepted. Good answer. – BWG Dec 26 '13 at 21:27
0

At the time a uses b it has been declared (because you wrote class b; above it) but not defined (the definition is below a). "Incomplete Type" means the type has been declared but not defined.

David
  • 27,652
  • 18
  • 89
  • 138