Reputation: 258588
This is related to a recent question.
Basically the following code:
class A
{
class B* b;
B* c;
};
compiles although class B
is not declared or forward-declared. Is this syntax equivalent to a forward declaration? Are there any differences?
Upvotes: 3
Views: 203
Reputation: 42083
I would like to add few details to answer of Charles Bailey:
class A
{
public:
class B * b;
class C {} *c;
int d;
} a;
B* globalB;
// C* globalC; identifier "C" is undefined here
int main(int argc, char *argv[])
{
a.d = 1;
cout << a.d;
}
Yes, it defines incomplete type B
and b
as a pointer to B
at once. But here comes the fun:
"An exception to the scope visibility of a nested class declaration is when a type name is declared together with a forward declaration. In this case, the class name declared by the forward declaration is visible outside the enclosing class, with its scope defined to be the smallest enclosing non-class scope." (Nested Class Declarations)
Which means that type B
is defined out of scope A
which allows you to define variable globalB
. If you don't want B
to be defined out of scope A
, you can use {}
just like it is used with type C
in my example.
By the way, this example is correct and its output is: 1
Upvotes: 1
Reputation: 791799
You can declare a type and an object in the same declaration.
class B* b;
Declares a type, B
and an object b
which has type pointer to B
. The type is incomplete and is looked up in the scope in which it occurs, if the lookup fails to find an existing declaration for the class then the type names a type in the nearest enclosing namespace scope (strictly non-class non-function-prototype scope, which is usually a namespace). The object is a member of the scope in which the declaration appears (in this case, class A
).
In most cases it's more common to declare a complete type and an object together, in this case the type is sometimes left anonymous. E.g.
struct { int a; int b; } x;
The relevant parts of the standard for the name scoping rules are 7.1.5.3 [dcl.type.elab] Elaborated type specifiers / 2 and the referenced sections in 3.4.4 and 3.3.1 :
3.4.4 describes how name lookup proceeds for the identifier in an elaborated-type-specifier. If the identifier resolves to a class-name or enum-name, the elaborated-type-specifier introduces it into the declaration the same way a simple-type-specifier introduces its type-name. If the identifier resolves to a typedef-name or a template type-parameter, the elaborated-type-specifier is ill-formed. [ ... ] If name lookup does not find a declaration for the name, the elaborated-type-specifier is ill-formed unless it is of the simple form class-key identifier in which case the identifier is declared as described in 3.3.1.
Upvotes: 9
Reputation: 46559
No, it's a declaration, of a pointer to B. You are not declaring B here, only a pointer to it, and there's nothing forward about it.
Edit: I was wrong, sorry. See other answer.
Upvotes: 1