Question

I know that I can do:

class Foo;

but can I forward declare a class as inheriting from another, like:

class Bar {};

class Foo: public Bar;

An example use case would be co-variant reference return types.

// somewhere.h
class RA {}
class RB : public RA {}

... and then in another header that doesn't include somewhere.h

// other.h
class RA;

class A {
 public:
  virtual RA* Foo();  // this only needs the forward deceleration
}

class RB : public RA; // invalid but...

class B {
 public:
  virtual RB* Foo();  // 
}

The only information the compiler should need to process the declaration of RB* B:Foo() is that RB has RA as a public base class. Now clearly you would need somewhere.h if you intend to do any sort of dereferencing of the return values from Foo. However, if some clients never calls Foo, then there is no reason for them to include somewhere.h which might significantly speed compilation.

Was it helpful?

Solution

A forward declaration is only really useful for telling the compiler that a class with that name does exist and will be declared and defined elsewhere. You can't use it in any case where the compiler needs contextual information about the class, nor is it of any use to the compiler to tell it only a little bit about the class. (Generally, you can only use the forward declaration when referring to that class without other context, e.g. as a parameter or return value.)

Thus, you can't forward declare Bar in any scenario where you then use it to help declare Foo, and it flat-out doesn't make sense to have a forward declaration that includes the base class -- what does that tell you besides nothing?

OTHER TIPS

Forward declarations are declarations, not definitions. So, anything that requires the declaration of a class (like pointers to that class) need only the forward declaration. However, anything that would require the definition - i.e. would need to know the actual structure of the class - would not work with just the forward declaration.

Derived classes definitely need to know the structure of their parent, not just that the parent exists, so a forward declaration would be insufficient.

No it is not possible to forward declare inheritance, even if you are only dealing with pointers. When dealing with conversions between pointers, sometimes the compiler has to know the details of the class to do the conversion correctly. This is the case with multiple inheritance. (You could special case some parts parts of the hierarchy that only use single inheritance, but that isn't part of the language.)

Consider the following trivial case:

#include <stdio.h>
class A { int x; };
class B { int y; };
class C: public A, public B { int z; };
void main()
{ 
    C c; A *pa = &c; B *pb = &c; C *pc = &c; 
    printf("A: %p, B: %p, C: %p\n", pa, pb, pc);
}

The output I received (using 32 bit visual studio 2010), is:

A: 0018F748, B: 0018F74C, C: 0018F748

So for multiple inheritance, when converting between related pointers, the compiler has to insert some pointer arithmetic to get the conversions right.

This is why, even if you are dealing only with pointers, you can't forward declare inheritance.

As for why it would be useful, it would improve compile times when you do want to make use of co-variant return types instead of using casts. For example this will not compile:

class RA;
class A             { public: virtual RA *fooRet(); };
class RB;
class B : public A  { public: virtual RB *fooRet(); };

But this will:

class RA;
class A             { public: virtual RA *fooRet(); };
class RA { int x; };
class RB : public RA{ int y; };
class B : public A  { public: virtual RB *fooRet(); };

This is useful when you have objects of type B (not pointers or references). In this case the compiler is smart enough to use a direct function call, and you can use the return type of RB* directly without casting. In this case, usually I go ahead and make the return type RA * and do a static cast on the return value.

I don't think it's useful. Consider: you have defined a class, Bar:

class Bar {
public:
    void frob();
};

Now you declare a class Foo:

class Foo;

All you can do with Foo is construct a pointer to it. Now, suppose you add the information that Foo is derived from Bar:

class Foo: public Bar;

What can you now do that you couldn't do before? I think that all you can do is accept a pointer to Foo and cast it into a pointer to Bar, then use that pointer.

void frob(Foo* f) {
    Bar *b = (Bar)f;
    b->frob();
}

However, you must have generated the pointer elsewhere, so you could have just accepted a pointer to Bar instead.

void frob(Bar* b) {
    b->frob();
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top