The following simple piece of code compiles, although I don't understand why:
class C {
class B;
class A {
B getB() { return B(); }
};
class B {
};
};
int main(int, char**)
{
return 0;
}
If I then comment out the "class C" stuff, so that the forward declaration of B, the definition of A and the definition of B are no longer nested within a class, the code does not compile, since B is of an incomplete type:
main.cpp: In member function 'B A::getB()':
main.cpp:6: error: return type 'struct B' is incomplete
main.cpp:6: error: invalid use of incomplete type 'struct B'
main.cpp:3: error: forward declaration of 'struct B'
I understand what it means for a type to be incomplete, namely that it has not been defined yet and so the compiler can't possibly know how much space to allocate for it. But why is B not considered incomplete in the code above, where A and B are both declared and defined inside of C?
I believe this is a consequence of [basic.scope.class]:
The potential scope of a name declared in a class consists not only of the declarative region following the
name’s point of declaration, but also of all function bodies, default arguments, exception-specifications, and brace-or-equal-initializers of non-static data members in that class (including such things in nested
classes).
That is, the scope of the full declaration of B includes the body of the member function of the nested class:
class C {
class B; // (1)
class A {
B getB() {
return B(); // both (1) and (2) in scope here
// since (2) is the complete type declaration,
// this is perfectly fine
}
};
class B { // (2)
};
};
By comparison, if C were a namespace instead of a class, the scope of the full declaration of class B would not extend into A::getB(). The only visible declaration would be the forward-declaration of B that I labeled (1) - so B() would be the construction of an incomplete type there.
The body of an inline member function is not processed until the class definition has been fully processed.
Hence, you can use:
class A
{
class B;
B getB() { return B(); }
class B {};
};
That also allows member variables that are not yet declared to be used in inline member function definition.
class Foo
{
int getBar() { return bar; }
int bar;
};
I am guessing the same logic is extended to inline definitions of member functions of nested classes -- i.e. they are not processed until the containing class definition is completely processed.
PS I am unable to quickly locate the reference in the standard that would verify my claim.
PS 2 The answer by Barry has the reference in the standard that makes the code in the question valid.
The standard is explicit in mandating that the method's body is interpreted after the class that encloses it.
Thus at the time of evaluating the body of C::A::getB(), A, B and C are all complete types.
Besides that when I've got the need to forward declare nested classes I tend to smell some bad design in my code, the trick I use is:
// Foo.h
class Foo {
class Bar {
};
};
class Foobar : public Foo::Bar {};
// Zoo.h
/* Fwd declare */
class FooBar;
Related
class B;
class A {
private:
int numA;
public:
A(): numA(12) { }
// friend function declaration
friend int add(A, B);
};
this does not give any error on declaring object of class B in friend
function,,but this gives,,as firstly class B is declared
class Apple;
class B {
private:
int b;
public:
void showA(Apple d)
{
// Since B is friend of A, it can access
// private members of A
cout << "A::a=" ;
}
};
};
this gives an error of incomplete type for object d,,why this is happening though we already declared class apple before,
Why does the first example compile?
In your first example, you have a forward declaration of class B followed by a declaration of a friend function that uses it in its parameter list:
class B;
class A {
...
friend int add(A, B);
};
This is allowed because, although B is incomplete, we are not defining add yet, only declaring an intention to eventually do so.
Why does the second example not compile?
In the second example, we have a forward declaration of class Apple, followed by a definition of showA:
class Apple;
class B {
...
void showA(Apple d)
{
...
}
};
This time, since we are defining the function, the compiler is obligated to generate code for it. But because Apple is incomplete, the compiler cannot know, for example, how much space in memory to reserve to hold the parameter d. Therefore this is an error.
The question When can I use a forward declaration? explains some of what can and cannot be done with an incomplete (forward-declared) type.
The use of 'friend' is irrelevant here
The friend keyword is basically irrelevant here. friend primarily affects access control (in the sense of public and private), but that's not the issue here.
A detail: friend also affects scoping. Because of friend, add is not a member of class A, but rather refers to a member of the global scope without actually introducing one (it's weird). But that does not change whether an incomplete type can be used as a parameter.
I just read this answer, and it completely puzzles me.
I was always thinking a class declaration can appear many times, and only the definition has to exist only once, like:
/*class Class {*/
class A; // (1) forward declaration
class A { // (2) definition, only once
int m;
};
class A; // (3) declaration again, legal?
class A a; // (4) declaration again, legal?
/*};*/
From the linked answer: (3) (and (4)?) is illegal if the code above is nested inside a class (definition and declarations of class A are nested inside class Class).
On cppreference, I found an example of the above, not nested:
struct s { int a; };
struct s; // does nothing (s already defined in this scope)
void g() {
struct s; // forward declaration of a new, local struct "s"
// this hides global struct s until the end of this block
s* p; // pointer to local struct s
struct s { char* p; }; // definitions of the local struct s
}
See the second line.
Question: Given that it is illegal inside a class, is my example code, and the cppreference example above, legal when not nested inside a class? Or more generally: When can a class declaration follow a definition (how is it inside namespaces for example)? If it is legal, why is there a difference?
From [basic.def]:
A declaration (Clause 7) may introduce one or more names into a translation unit or redeclare names introduced by previous declarations.
From [class.name]:
A declaration consisting solely of class-key identifier; is either a redeclaration of the name in the current scope or a forward declaration of the identifier as a class name. It introduces the class name
into the current scope.
So it's generally legal to do this. There's just the one exception in [class.mem]:
A member shall not be declared twice in the member-specification,
except that a nested class or member class template can be declared and then later defined, and except that an enumeration can be introduced with an opaque-enum-declaration and later redeclared with an enum-specifier.
Perfectly OK in namespace scope, not allowed in class scope.
As to why? Well, this rule let's you "forward" declare all the classes you need everywhere you would typically be allowed to do so:
// a.h
struct C;
struct A {
C* c;
};
// b.h
struct C;
struct B {
C& c;
};
without having to worry about somebody actually including the full declaration and breaking everything for you:
// d.h
#include "c.h"
#include "a.h" // now C was already declared!
#include "b.h" // and here too!
struct D { ... };
This isn't so much of a concern within a class definition. It can't exactly span multiple files. So the inability to redeclare nested types doesn't actually achieve anything.
class A; This is a forward declaration of incomplete class A (legal).
class A { int m; }; This is the definition of Class A (legal).
class A; This is re-declaration of class A (legal).
class A a; This is declaration of object a of type A (legal).
I complied the following code, and get
error: incomplete type ‘AB::B’ used in nested name specifier
class B; //declareation
namespace A
{
class myException():public std::exception
{
public:
myException():std::exception()
{
B::b2(); //error: incomplete type ‘A::B’ used in nested name specifier
}
};
class B()
{
static void b1()
{
throw myException();
}
static void b2()
{
//code
}
};
};
I think I got a circular dependency between these two classes. Is it the reason that cause the error?
How can I get arround the circular dependency?
Thanks a lot
I think I got a circular dependency between these two classes.
Not between the classes themselves; but each has member functions that depend on the other class, so as written there is a circular dependency.
Is it the reason that cause the error?
Yes. Each member function definition has to come after the class that it uses; which is impossible if they are defined in the class.
How can I get arround the circular dependency?
Move the definition of at least one of the member functions out of its class, to a point at which the other class is defined. If these are in a header, intended to be included from multiple source files, then either move the definition to a source file, or to later on in the header with an inline specifier.
For example, you could move the constructor of myexception, leaving just a declaration in the class:
class myException():public std::exception
{
public:
myException(); // OK: no use of incomplete type here
};
and define it either inline, after the definition of B, or in a source file that includes this header:
inline // if defined in a header
myException::myException() // no need to explicitly initialise std::exception
{
B::b2(); // OK: B is complete now
}
First of all,
class B; //declareation
namespace A
{
declares B to be a class in the global namespace, not in namespace A. Hence, the use of
B::b2();
later in the code expects b2 to be a member of the global B. I think you meant to forward declare the B in namespace A. For that, you need to use:
namespace A
{
class B; //declareation
To remove the circular dependencies between the class definitions and the member function implementations, move the member function implementations after the classes have been defined. Then, you don't need the forward declaration of B at all. It won't hurt if it's there, but it's not necessary.
namespace A
{
// Optional.
class B;
// Class definitions without the member function implementations
class myException(): public std::exception
{
public:
myException();
};
class B()
{
public:
static void b1();
static void b2();
};
// Class member function implementations
inline myException::myException(): std::exception()
{
B::b2();
}
inline void B::b1()
{
throw myException();
}
inline void B::b2()
{
//code
}
}
In this point
class B; //declareation
//...
myException():std::exception
{
B::b2(); //error: incomplete type ‘A::B’ used in nested name specifier
}
the compiler does not know whether class B has member b2 because class B is not defined yet. So the compiler issues an error because it does not know what expression b2() means.
Also this statement
myException():std::exception
contains a syntaxical error. I think you mean
myException():std::exception()
You have to define the constructor after the definition of class B.
Is there any way to redeclare a class to define methods which where only declared this far?
Eg. something like:
class A
{
void a();
void b() {}
}
class A
{
void a() {}
}
instead of
class A
{
void a();
void b() {}
}
A::a() {}
The reason is I created a lot of code with methods defined inside the class defintion, without using headers. I do not had cyclic references up to now, but recently there is need to. I don't like to define bunches of methods by the Type::method syntax, as only very few methods have to be known before the latter definition of the class.
So I like somewhat like a backward declaration, declare or define only a few methods before for cyclic references and define the whole class later.
No, there is no way to redefine a class.
According to the C++ language standard the class definitions is:
class-specifier:
class-head { member-specification_opt }
The standard explicitly says that member specification should be complete within class definition:
Members of a class are data members, member functions (9.3), nested types, and enumerators. The member-specification in a class definition declares the full set of members of the class; no member can be added elsewhere.
Also the standard gives example of redefinition of class:
struct S { int a; };
struct S { int a; }; // error, double definition
is ill-formed because it defines S twice.
Unfortunately there is no way to declare the class again once it is Closed with }.
Only thing you can do is you can inherit and define the method.
class B : public A { a() {} } ;
I know we can not define functions taking incomplete type as parameter, so it is expected the below code fails to compile with error C2027: use of undefined type 'Derived'
class Derived;
class Base{
public:
void test(Derived d){ cout<<"test"<<endl; }
};
class Derived : public Base{
int j;
};
By the same logic, I would expect compilation to fail when test() takes an object of Base, which is of incomplete-type till that point. However, it does not, and the following code compiles fine
class Derived;
class Base{
public:
void test(Base b){ cout<<"test"<<endl; }
};
class Derived : public Base{
int j;
};
Is there a difference between the incomplete class type we have while a class is being defined and the incomplete-type exposed by a forward declaration?
The logic is not the same. The difference is that in your second example function Base::test() uses objects of its own class Base (as opposed to a completely foreign class Derived).
The language gives a special treatment to this situation in 8.3.5/6 (C++03)
The type of a parameter or the return type for a function definition
shall not be an incomplete class type (possibly cv-qualified) unless
the function definition is nested within the member-specification for
that class (including definitions in nested classes defined within the
class).
This rule can be seen as a "satellite" for another similar rule - the one that says that the class type is always seen in its entirety (and as complete type) from bodies of class member functions, default arguments and constructor initializer lists. See 9.2/2 (C++03)
A class is considered a completely-defined object type (3.9) (or complete type) at the closing } of the
class-specifier. Within the class member-specification, the class is regarded as complete within function
bodies, default arguments and constructor ctor-initializers (including such things in nested classes). Otherwise
it is regarded as incomplete within its own class member-specification.
Note that in all other contexts before the closing } the class is considered to be incomplete
struct S {
S foo(S s) // <- OK, due to 8.3.5/6
{ return s; }
void bar(int a = sizeof(S)) // <- OK, due to 9.2/2
{ S s; } // <- OK, due to 9.2/2
int (*baz())[sizeof(S)] // <- ERROR: incomplete type in `sizeof`
{ return NULL; }
void qux(int a[sizeof(S)]) // <- ERROR: incomplete type in `sizeof`
{}
};