Forward Declaration

In the PascalLanguage, a way to enable one pass compilers with the compiler technology known at the time NiklausWirth designed Pascal.


In CeePlusPlus, a way to reduce module interdependencies, by reducing the number of necessary includes. A forward looks like this:

  class AClass;

As long as your public interface uses only references and/or pointers to such a class, this is enough to define said interface. Essentially, a forward says "there is a class named AClass", without defining any further detail.


Some people are surprised to learn C++ forward references even work in cases like:

    class Server; // The forward reference.

class Client { public: virtual Server server() const; virtual void setServer( Server server ); };

It is a surprise because it uses the Server class itself, not a reference or pointer to it. It works because the methods are only being declared, not defined. The compiler does not emit any code or do anything which requires it to know the size or interface of Server. -- DaveHarris

Hmmm... My compiler doesn't accept this. It only will if I change the references of Server to Server&.

I don't know how Dave got the idea, but in both cases methods of the class are invoked (the copy ctor), and thus the class definition is needed. Probably it worked for him because of the broken VisualCeePlusPlus PrecompiledHeader?s implementation.

Even if it didn't invoke the copy ctor, how would the compiler know how many bytes to use in the parameter and return stacks for clients of this class? And, if it only works with the declaration but no code that includes this header, then what is the use?

This has been discussed on the moderated C++ newsgroups and I believe it is required by the C++ standard (though I don't have a good reference for that). Copy the code exactly as given. You can't add code which actually calls or defines the functions.

The point is, the compiler doesn't need to know how many bytes to use in the return stack because the declarations do not generate actual code. Think about it. The functions are not inline and are not called. If the copy constructor is private, say, then calls or definitions would be illegal but the declaration itself is not. And the compiler has enough info to resolve static overloading. There is nothing which requires the full declaration.

For comparison, this:

    class Server {
    private:
        Server();
        Server( const Server &server );
        ~Server();
    };

class Client { public: virtual Server server() const; virtual void setServer( Server server ); };

also compiles, even though the copy constructor is private. This:

    class Server;

class Client { public: virtual Server server() const {}; virtual void setServer( Server server ); };

does not compile because it generates code that actually needs the copy constructor. This:

    class Server;

class Client { Server s; public: virtual Server server() const {}; virtual void setServer( Server server ); };

does not compile either, because sizeof(Server) is needed to lay out Client. Is it possible you typed one of these into your compiler instead of the original example?

I guess if this doesn't convince you we need recourse to a higher authority to decide which compiler is broken. -- DaveHarris

I don't see why you'd need to include the type definition of Server. Here's a C++ Rule of Thumb to get you through tricky thinking: "If the compiler doesn't need it, you won't have to do it." C++ is well optimized.

By the way, it is true that you cannot actually use Client (as it stands now) unless you have included the definition of Server. But you don't have to necessarily include that inside the same header file. In fact, that's the point of forward declarations.

If you want to see an example using Client, some modifications have to be made. The virtuals have to go and methods independent of Server need to be added. Here's some more example code to try:

 class Server; // The forward reference.

class Client { public: Server server() const; void setServer( Server server ); void nop() {} };

main() { Client foo; foo.nop(); return 0; }

-- SunirShah


Embedded forward declarations

When you refer to a class defined within a C++ namespaces, simply place the forward declaration in an enclosing namespace declaration:

 namespace MyNamespace? { class MyClass; }

Forward declarations can also be used within class (or structure) definitions:
 class MyClass {
   class SomePrivateClass?;
   // some use of SomePrivateClass?
 };
For defining the embedded class, use this syntax:
 class MyClass::SomePrivateClass? {
 // actual definition
 };

-- WolfPeuker?


CategoryCpp


EditText of this page (last edited August 27, 2013) or FindPage with title or text search