Am I missing something here?
class Foo;
class Bar {
public:
Foo foo;
};
class Foo { };
Error:
error C2079: 'Bar::foo' uses undefined class 'Foo'
When you forward-declare a class, you can make pointers and references to it, but you cannot make members of the type of forward-declared class: the full definition of Foo is needed to decide the layout of the outer class (i.e. Bar), otherwise the compiler cannot make a decision on the size and the structure of Bar.
This is allowed, though:
class Foo;
class Bar {
public:
Foo* fooPtr;
Foo& fooRef;
};
The reason the pointers and references to forward-declared classes are allowed is that the sizes of pointers and references do not depend on the structure of the class to which they point (or which they reference).
Yes you are missing something important: A question.
I assume you want to know what's wrong in the code, and why the compiler issues an error.
The compiler has to know the size of Foo in order to calculate the layout of the class Bar. The size of Foo objects is determined by their layout, to know that layout, the compiler has to know the class definition. At the point where you declare the Member variable foo, it merely knows that Foo exists, but not its size, because you have given it only a declaration, not a definition before.
Related
It is well-known that one cannot have a member of the type you're defining:
class Foo {
Foo member;
};
The reason is that this is an infinitely recursive, infinitely large object. However, we can have static members:
class Foo {
static Foo member;
};
We can do this because Foo is acting like a namespace; instances of Foo do not contain .member, so there's no infinite reference. Put another way, .member belongs to the class, not to the instance. What I would like to do is very similar:
class Foo {
class Bar {
Foo member;
};
};
Once again, Foo is acting like a namespace. Instances of Foo are actually empty. I would have to make a non-static field Bar Foo::bar; to start getting layout issues. Unfortunately, my compilers disagree (e.g. GCC):
<source>:3:14: error: field 'member' has incomplete type 'Foo'
Foo member;
^~~~~~
For what technical reason is this not allowed?
Long story short, it was easier to disallow this than to allow.
Here is an example that shows what could be difficult about it: C++ lets you combine nested class definition with a member declaration, like this:
class Foo {
class Bar {
Foo member;
} bar; // <<== Here
};
It is clear why this definition must be disallowed: unlike a class definition which could have been OK, member definition makes size computation impossible.
Of course the writers of the standard could have allowed class definitions to pass, at the expense of giving compiler writers additional work. However, it looks like they decided that allowing this feature is not worth the trouble, so they didn't make it an exception from the requirement of the class to be complete at the point of declaring an instance.
There is nothing wrong with what you what to do, and you can do so with different syntax.
Since the compiler wants to determine the size of class Bar, it needs to know the size of class Foo, But Foo's definition is not yet complete (The source code has not been entirely parsed by the compiler). The definition of Foo must be completed before using it in Bar.
Instead try forward declaring Bar inside Foo, then completing the definition of Bar after Foo, This way the size of Foo can be determined for use in Bar.
class Foo {
class Bar;
};
class Foo::Bar {
Foo member;
};
It's not allowed because you can't define a class with a member with an incomplete type, period. At the end of the class definition the class becomes complete and that is only possible if the sizes of all of its members are known.
For example, you get the same error, for the same reason, without nesting classes like this:
class Foo;
class Bar {
Foo member;
};
Sure, in your example the language could defer completing the definition of Foo::Bar until Foo is defined, but this would be inconsistent with how classes are defined generally. You'd have the weird behaviour of Foo::Bar being incomplete at a point in the source code after it was fully defined.
I have a basic question that has bothered me for sometime.
When using a Class within a Class I can define the header of the Class I want to use in the header file. I have seen two ways of doing this and would like to know the difference between the two methods?
ex1
#include "ClassA.h"
class ClassB {
public:
ClassB();
~ClassB();
ClassA* a;
};
#endif
ex2 Here is the other way of doing it. The ClassA Header would be defined in ClassB source file.
class ClassA;
class ClassB {
public:
ClassB();
~ClassB();
ClassA* a;
};
#endif
What are the differences with these two methods?
The comlpete layout of the classA is known to the compiler when you include the class definition.
The second syntax is called Forward declaration and now classA is an Incomplete type for the compiler.
For an Incomplete type,
You can:
Declare a member to be a pointer or a reference to the incomplete type.
Declare functions or methods which accepts/return incomplete types.
Define functions or methods which accepts/return pointers/references to the incomplete type (but without using its members)
But You cannot:
Use it as a base class.
Use it to declare a member.
Define functions or methods using this type.
Use its methods or fields, in fact trying to dereference a variable with incomplete type.
So Forward Declaring the class might work faster, because the complier does not have to include the entire code in that header file but it restricts how you can use the type, since it becomes an Incomplete type.
The second method only allows you to create pointers to ClassA, as it's size is unknown. It may however compile faster as the header for the full definition for ClassA is not included.
The latter is a forward declaration. This way you can declare a pointer or reference to a class, even though you have not yet fully declared it. This can be used to resolve cyclic dependencies. What if, in your first example, A also wants to use a pointer to B. This wouldn't work, because when A is declared, B is not known yet. To solve this, you can use a forward declaration to tell the compiler that there is a class B, and you will tell it later what it looks like.
I have a class that I made that I am using in thread above the class. Even though I did a prototype of the class at the top it still throws off those errors
error C2027: use of undefined type 'foo'
class foo;
DWORD WINAPI demo(LPVOID param)
{
foo a;
}
class foo
{
public:
int x;
};
Even though I did a prototype of the
class
With a forward declaration of the class you can create pointers and references to the class. This is because pointers/references are represented the same across all classes/structs/etc. They're all just addresses of memory. So, for example, you could create a second class that can accept or contains pointers or references before fully defining the class, ie:
class Bar
{
private:
foo* aFoo;
public:
Bar(foo* foo2) : aFoo(foo2) {}
};
However, until the compiler sees the full definition of the class, you can't instantiate it. Otherwise the compiler doesn't know how much memory to allocate and how to call the constructor and other methods. In most cases, C++ expects things to be defined before they are used. Forward declaration lets you get around this a little bit because pointers and references for any class are identical. So you can promise to the compiler you'll fully define it later.
I have a simple code below:
class B;
class A{
B b;
};
class B{
public:
B(){
}
};
In class A's definition, I have a B-typed property. Using MS Visual Studio to compile, I've got the following error:
error C2079: 'A::b' uses undefined class 'B'
Due to some reasons, I can't put class B's definition before class A's one. Any idea?
The compiler is already telling you what's wrong : A has a member data b which is of an undefined type. Your forward declaration:
class B;
is just that : a declaration, not a definition. Since class A contains an instance of B directly (not just a pointer to B), the compiler needs to know the exact size of B : it needs its definition, not just a declaration, i.e. a promise that B will exist at some point.
The simplest thing to do here would be to reorder things this way:
class B{
public:
B(){
}
};
class A{
B b;
};
Edit : see also this question for the difference between declaration and definition.
Further edit : an alternative would be to change your member data to a pointer or a reference.
Do note that this isn't a trivial syntax change: it has implications on the life-cycle of your objects since the object pointed by A::b may then survive the destruction of A.
If what you want is composition (B is a part of A and dies with A), using a pointer will make your life harder with little benefits.
More edits(!) : just realized I misread the end of your question; what are the reasons preventing you from declaring B before A ?
If they cannot be worked around, you may have to go the pointer route. These reasons might be a sign that your objects are too tightly coupled though ! (perhaps B needs to be an inner class of A ? Or simply be merged into a single object ?)
class A;
class B {
A * getA();
};
class A {
B b;
};
This is the typical way to solve this. You must have B's definition in order to have a B b; member.
You need a forward declaration in order to declare a reference/pointer to B, you need the full definition in order to do anything else with B (such as defining a variable, calling a member function and so on)
You can do what you wish if you change the reference to b into a pointer to B.
class A{
B* bPtr;
};
class B{
public:
B(){
}
};
In principle, you don't need an explicit declaration - that is, a forward declaration is all that is needed - when you don't need the actual size of the class, or access to the types and member functions inside the class.
In your original example, you are making a direct reference to B. As a result, the compiler needs to know everything about B, thus requiring an explicit declaration instead of a forward one.
By having your A class declaration using a pointer to B, then you can get away with a forward declaration.
edit
Some links might explain the concept for you:
http://www.goingware.com/tips/parameters/notrequired.html
http://www-subatech.in2p3.fr/~photons/subatech/soft/carnac/CPP-INC-1.shtml
http://www.codeguru.com/forum/showthread.php?t=358333 (see post #2)
http://en.wikipedia.org/wiki/Forward_declaration
C++ has the concept of an "incomplete" class and it is something you need to know.
Using an incomplete class allows you, in many situations, to use a class just knowing it is one, without knowing what is in it.
This enables the class detail to change later without requiring a recompile, thus it is a far weaker dependency in the coupling model.
You need a complete class to:
Have an instance of one.
Derive from it
Call any method on it.
delete a pointer to it.
You only need an incomplete class to:
Hold a pointer or reference to it.
Pass a pointer or reference to a function that takes a pointer or reference. (This can be a function that deletes the pointer, as long as it is fully defined at that point).
I think you only need an incomplete class to declare a function that returns one, and possibly to declare a function that takes one as a parameter, but at the time you define or call the function it needs to be complete, even if you don't use the return value.
I just stumbled a c++ code with a calling of a class name in the upper part of the header file for example
class CFoo;
class CBar
{
....
};
My question is, what is class CFoo for?
Thanks alot!
This is called a forward declaration. It means that there IS a class named CFoo, that will be defined later in the file (or another include). This is typically used for pointer members in classes, such as:
class CFoo;
class CBar {
public:
CFoo* object;
};
It is a hint to the C++ compiler telling it not to freak out that a type name is being used without being defined, even though it hasn't seen the full definition for CFoo yet.
It's called a forward declaration.
http://en.wikipedia.org/wiki/Forward_declaration
class CFoo;
Is just a declaration that the class exists; even if you haven't seen the definition yet, you can still play with (CFoo *) or (CFoo &) - that is, pointers and references to CFoo.