[ACCEPTED]-Forward Declaration of a Base Class-forward-declaration

Accepted answer
Score: 29

The first problem you can't solve.

The second 26 problem is not anything to do with standard 25 library classes. It's because you declare 24 an instance of the class as a member of 23 your own class.

Both problems are due to 22 the requirement that the compiler must be 21 able to find out the total size of a class 20 from its definition.

However, the compiler 19 can work out the size of a pointer to a 18 class, even if it doesn't yet have the full 17 definition of it. So a possible solution 16 in such cases is to have a pointer (or reference) member 15 in the consuming class.

Not much help in 14 the base class case, because you won't get 13 an 'is a' relationship.

Nor is it worth doing 12 for something like std::string. Firstly, it's supposed 11 to be a convenient wrapper around a character 10 buffer, to save you from doing memory management 9 on something so simple. If you then hold 8 a pointer to it, just to avoid including 7 the header, you're probably taking a good 6 idea too far.

Secondly (as pointed out in 5 a comment), std::string is a typedef to std::basic_string<char>. So you need 4 to forward declare (and then use) that instead, by 3 which time things are getting very obscure 2 and hard to read, which is another kind 1 of cost. Is it really worth it?

Score: 7

As answered before by Earwicker, you can 38 not use forward declarations in any of those 37 cases as the compiler needs to know the 36 size of the class.

You can only use a forward 35 declaration in a set of operations:

  • declaring functions that take the forward declared class as parameters or returns it
  • declaring member pointers or references to the forward declared class
  • declaring static variables of the forward declared type in the class definition

You cannot 34 use it to

  • declare a member attribute of the given type (compiler requires size)
  • define or create an object of the type or delete it
  • call any static or member method of the class or access any member or static attribute

(did I forget any?)

Take into account 33 that declaring an auto_ptr is not the same as declaring 32 a raw pointer, since the auto_ptr instantiation 31 will try to delete the pointer when it goes 30 out of scope and deleting requires the complete 29 declaration of the type. If you use an auto_ptr in 28 to hold a forward declared type you will 27 have to provide a destructor (even if empty) and 26 define it after the full class declaration 25 has been seen.

There are also some other 24 subtleties. When you forward declare a class, you 23 are telling the compiler that it will be 22 a class. This means that it cannot be an 21 enum or a typedef into another type. That is the problem 20 you are getting when you try to forward 19 declare std::string, as it is a typedef of a specific 18 instantiation of a template:

typedef basic_string<char> string; // aproximate

To forward declare 17 string you would need to forward declare 16 the basic_string template and then create the typedef. The 15 problem is that the standard does not state 14 the number of parameters that basic_string template 13 takes, it just states that if it takes more 12 than one parameter, there rest of the parameters 11 must have a default type so that the expression 10 above compiles. This means that there is 9 no standard way for forward declaring the 8 template.

If, on the other hand you want 7 to forward declare a non-standard template 6 (non STL, that is) you can do it for as 5 long as you do know the number of parameters:

template <typename T, typename U> class Test; // correct
//template <typename T> class Test; // incorrect even if U has a default type

template <typename T, typename U = int> class Test {
   // ...
};

At 4 the end, the advice that was given to you 3 by Roddy: forward declare as much as you 2 can, but assume that some things must be 1 included.

Score: 3

In both cases the compiler needs to know 9 the size of the type. Therefore, a forward 8 declaration will not suffice. A base class 7 could add members or require a virtual table. The 6 string member would require the size of 5 the class to be increase to store the size 4 of the STL string class.

Forward declaring 3 STL classes is often inadvisable since the 2 implementations commonly include explicit 1 template instantiations that speed up compilation.

Score: 2

You're trying too hard to solve something 6 that isn't actually a problem. Use the header 5 files you need, and reduce - WHERE POSSIBLE 4 - the requirement for them. But don't try 3 and take it to extremes because you'll fail.

In 2 some cases, the PIMPL idiom may help you, but 1 not here.

Score: 1

For your base classes, you need to have 10 the full type definition, not just a declaration. Derived 9 type headers will need to #include the header 8 for their base classes.

For classes in the 7 std namespace, you must include the proper 6 header - <string> in this case - and 5 then do one of 3 things:

  1. Fully qualify the 4 type: std::string aStringToTest

  2. Put a using 3 declaration for just that type: using std::string;

  3. Put 2 in a using declaration for the std namespace: using 1 namespace std;

Score: 1

> Seems that forward declaration is useless 13 for base classes and stl classes.

Correction... Forward 12 declaration is INAPPROPRIATE for base classes 11 and object member. (It's not "useless", it 10 is "inapplicable".)

A base class 9 MUST be declared (not forward declared) when 8 being declared as a based class of another 7 class.

An object member MUST be declared 6 (not forward declared) when being declared 5 by another class, or as parameter, or as 4 a return value. NOTE: by-reference or by-pointer 3 does not have that constraint.

Correction... Forward 2 declaration of STL classes is -- as per 1 ISO 14882 -- undefined behavior. http://www.gotw.ca/gotw/034.htm

More Related questions